+function ($) {
    "use strict";
    var defaults = {
        pageLoading: true, //页面加载指示器
        router: true, //默认使用router
		direction:'left', //默认过渡动画
        swipePanel:true, //滑动打开侧栏
		changeBrowserTitle:true, //是否改变浏览器title
		browserSpringback:true,//是否禁用浏览器回弹
        swipePanelOnlyClose: false,  //只允许滑动关闭，不允许滑动打开侧栏
		clickAudioPlay:{ //按键音
			state:false,
			mp3: "audio/b1.mp3",
			ogg: "audio/b1.ogg",
		},
		indexedDB:{
			dbName :'ansicht',
			storeName:'storage'
		}
    };
    $.smConfig = $.extend(defaults, $.config);
}($);

(function($) {
    "use strict";
    $.support = (function() {
        var support = {
            touch: !!(('ontouchstart' in window) || window.DocumentTouch && document instanceof window.DocumentTouch)
        };
        return support;
    })();

	$.compareVersion = function(a, b) {
        var as = a.split('.');
        var bs = b.split('.');
        if (a === b) return 0;
        for (var i = 0; i < as.length; i++) {
            var x = parseInt(as[i]);
            if (!bs[i]) return 1;
            var y = parseInt(bs[i]);
            if (x < y) return -1;
            if (x > y) return 1;
        }
        return -1;
    };

    $.getCurrentPage = function() {
		var $page = $('.page-current').eq(0);
		if (!$page) $page = $('.page').eq(0).addClass('page-current');
		if (!$page) $page = $(document.body);
        return $page;
    };

	//网络状态
	$.network = function(option){
		var defaults = {
			online:function(){},
			offline:function(){}
		}
		var networkState;
		var opts = $.extend(defaults, option);
		var onLine = navigator.onLine;
		if(onLine){
			networkState = 'online';
			opts.online.call()
		}else{
			networkState = 'offline';
			opts.offline.call()
		}

		window.addEventListener("online",function(){
			networkState = 'online';
			opts.online;
		},false);
		window.addEventListener("offline",function(){
			networkState = 'offline';
			opts.offline;
		},false);

		return networkState;
	};
	//接收url 参数
	$.request = function(name,str){
		var reg = new RegExp("(^|&)"+ name +"=([^&]*)(&|$)");
		var r   = str == '' ? str : window.location.search.substr(1) ;
		var r = r.match(reg);
		if(r!=null) return unescape(r[2]); return null;
	};

	//显示工具栏
	$.showBartab = function() {
		$('.bar-tab').addClass('show-bar-tab').removeClass('no-bar-tab');
	};

	//隐藏工具栏
	$.hideBartab = function() {
		$('.bar-tab').addClass('no-bar-tab').removeClass('show-bar-tab');
	};

	$.inScript = function(script,element) {
		if (!script) return;
		for (var i = 0; i < script.length; i++) {
			if (script[i].src == element) {
				return true;
			}
		}
		return false;
	};

	//构造url
	$.buildUrl = function(param, key){
		var paramStr = '';
		if(typeof param === 'object'){
			$.each(param,function(i,value){
				var k=key==null?i:key+(param instanceof Array?"["+i+"]":"."+i);
				paramStr+='&'+$.buildUrl(value, k);
			});
		}else{
			paramStr+= "&" + key + "=" + encodeURIComponent(param);
		}
		return paramStr.substr(1);
	};

	//删除参数
	$.removeUrl= function(url, param){
		var str = "";
		if (url.indexOf('?') != -1)
			str = url.substr(url.indexOf('?') + 1);
		else
			return url;
		var arr = "";
		var returnurl = "";
		var setparam = "";
		if (str.indexOf('&') != -1) {
			arr = str.split('&');
			for (var i in arr) {
				if (arr[i].split('=')[0] != param) {
					returnurl = returnurl + arr[i].split('=')[0] + "=" + arr[i].split('=')[1] + "&";
				}
			}
			return url.substr(0, url.indexOf('?')) + "?" + returnurl.substr(0, returnurl.length - 1);
		}
		else {
			arr = str.split('=');
			if (arr[0] == param)
				return url.substr(0, url.indexOf('?'));
			else
				return url;
		}
	};

	$.getTouchPosition = function(e) {
		e = e.originalEvent || e;
		if(e.type === 'touchstart' || e.type === 'touchmove' || e.type === 'touchend') {
		  return {
			x: e.targetTouches[0].pageX,
			y: e.targetTouches[0].pageY
		  };
		} else {
		  return {
			x: e.pageX,
			y: e.pageY
		  };
		}
	};

    $.touchEvents = {
        start: $.support.touch ? 'touchstart' : 'mousedown',
        move: $.support.touch ? 'touchmove' : 'mousemove',
        end: $.support.touch ? 'touchend' : 'mouseup'
    };

    $.getTranslate = function (el, axis) {
        var matrix, curTransform, curStyle, transformMatrix;

        // automatic axis detection
        if (typeof axis === 'undefined') {
            axis = 'x';
        }

        curStyle = window.getComputedStyle(el, null);
        if (window.WebKitCSSMatrix) {
            // Some old versions of Webkit choke when 'none' is passed; pass
            // empty string instead in this case
            transformMatrix = new WebKitCSSMatrix(curStyle.webkitTransform === 'none' ? '' : curStyle.webkitTransform);
        }
        else {
            transformMatrix = curStyle.MozTransform || curStyle.transform || curStyle.getPropertyValue('transform').replace('translate(', 'matrix(1, 0, 0, 1,');
            matrix = transformMatrix.toString().split(',');
        }

        if (axis === 'x') {
            //Latest Chrome and webkits Fix
            if (window.WebKitCSSMatrix)
                curTransform = transformMatrix.m41;
            //Crazy IE10 Matrix
            else if (matrix.length === 16)
                curTransform = parseFloat(matrix[12]);
            //Normal Browsers
            else
                curTransform = parseFloat(matrix[4]);
        }
        if (axis === 'y') {
            //Latest Chrome and webkits Fix
            if (window.WebKitCSSMatrix)
                curTransform = transformMatrix.m42;
            //Crazy IE10 Matrix
            else if (matrix.length === 16)
                curTransform = parseFloat(matrix[13]);
            //Normal Browsers
            else
                curTransform = parseFloat(matrix[5]);
        }

        return curTransform || 0;
    };

    $.requestAnimationFrame = function (callback) {
        if (requestAnimationFrame) return requestAnimationFrame(callback);
        else if (webkitRequestAnimationFrame) return webkitRequestAnimationFrame(callback);
        else if (mozRequestAnimationFrame) return mozRequestAnimationFrame(callback);
        else {
            return setTimeout(callback, 1000 / 60);
        }
    };
    $.cancelAnimationFrame = function (id) {
        if (cancelAnimationFrame) return cancelAnimationFrame(id);
        else if (webkitCancelAnimationFrame) return webkitCancelAnimationFrame(id);
        else if (mozCancelAnimationFrame) return mozCancelAnimationFrame(id);
        else {
            return clearTimeout(id);
        }
    };

	$.serializeObject = function (obj) {
		if (typeof obj === 'string') return obj;
		var resultArray = [];
		var separator = '&';
		for (var prop in obj) {
			if (obj.hasOwnProperty(prop)) {
				if ($.isArray(obj[prop])) {
					var toPush = [];
					for (var i = 0; i < obj[prop].length; i ++) {
						toPush.push(encodeURIComponent(prop) + '=' + encodeURIComponent(obj[prop][i]));
					}
					if (toPush.length > 0) resultArray.push(toPush.join(separator));
				}
				else {
					resultArray.push(encodeURIComponent(prop) + '=' + encodeURIComponent(obj[prop]));
				}
			}

		}
		return resultArray.join(separator);
    };

	/**
	 * 判断浏览器是否支持 sessionStorage，支持返回 true，否则返回 false
	 * @returns {Boolean}
	 */
	$.supportStorage = function() {
		var mod = 'sm.router.storage.ability';
		try {
			sessionStorage.setItem(mod, mod);
			sessionStorage.removeItem(mod);
			return true;
		} catch(e) {
			return false;
		}
	};

    function __dealCssEvent(eventNameArr, callback) {
        var events = eventNameArr,
            i, dom = this;

        function fireCallBack(e) {
            if (e.target !== this) return;
            callback.call(this, e);
            for (i = 0; i < events.length; i++) {
                dom.off(events[i], fireCallBack);
            }
        }
        if (callback) {
            for (i = 0; i < events.length; i++) {
                dom.on(events[i], fireCallBack);
            }
        }
    }

    $.fn.animationEnd = function(callback) {
        __dealCssEvent.call(this, ['webkitAnimationEnd', 'animationend'], callback);
        return this;
    };
    $.fn.transitionEnd = function(callback) {
        __dealCssEvent.call(this, ['webkitTransitionEnd', 'transitionend'], callback);
        return this;
    };

	 $.fn.transition = function(duration) {
        if (typeof duration !== 'string') {
            duration = duration + 'ms';
        }
        for (var i = 0; i < this.length; i++) {
            var elStyle = this[i].style;
            elStyle.webkitTransitionDuration = elStyle.MozTransitionDuration = elStyle.transitionDuration = duration;
        }
        return this;
    };
    $.fn.transform = function(transform) {
        for (var i = 0; i < this.length; i++) {
            var elStyle = this[i].style;
            elStyle.webkitTransform = elStyle.MozTransform = elStyle.transform = transform;
        }
        return this;
    };

	$.fn.dataset = function() {
        var dataset = {},
            ds = this[0].dataset;
        for (var key in ds) { // jshint ignore:line
            var item = (dataset[key] = ds[key]);
            if (item === 'false') dataset[key] = false;
            else if (item === 'true') dataset[key] = true;
            else if (parseFloat(item) === item * 1) dataset[key] = item * 1;
        }
        // mixin dataset and __eleData
        return $.extend({}, dataset, this[0].__eleData);
    };

    //重置$的show方法，防止有些人引用的版本中 show 方法操作 opacity 属性影响动画执行
    $.fn.show = function(){
        var elementDisplay = {};
        function defaultDisplay(nodeName) {
            var element, display;
            if (!elementDisplay[nodeName]) {
                element = document.createElement(nodeName);
                document.body.appendChild(element);
                display = getComputedStyle(element, '').getPropertyValue("display");
                element.parentNode.removeChild(element);
                display === "none" && (display = "block");
                elementDisplay[nodeName] = display;
            }
            return elementDisplay[nodeName];
        }

        return this.each(function(){
            this.style.display === "none" && (this.style.display = '');
            if (getComputedStyle(this, '').getPropertyValue("display") === "none");
            this.style.display = defaultDisplay(this.nodeName);
        });
    };
})($);

+function($){
	var storage = function(){
		var p = this;
		p.init = function(){
			try{
				var indexedDB  = window.indexedDB || window.webkitIndexedDB || window.mozIndexedDB || window.msIndexedDB;
				var request  = indexedDB.open($.smConfig.indexedDB.dbName);
					request.onerror = function(e){
						console.warn("open indexedDB Error: " + e.target.errorCode);
					};

					request.onupgradeneeded = function(e){
						var db = e.target.result;
						if(!db.objectStoreNames.contains($.smConfig.indexedDB.storeName)) {
							var objectStore = db.createObjectStore($.smConfig.indexedDB.storeName,{keyPath: "timeStamp"});
								objectStore.createIndex("url","url",{unique:false});
						}
					};
					return request;
			}catch(e){
				return false;
			}
		}
		p.imgToBase64 = function(url,i,callback){

			var xhr = new XMLHttpRequest();
			xhr.onload = function(e) {
				var reader = new FileReader();
				reader.readAsDataURL(xhr.response);
				reader.onload = function(e){
					if (callback){
						callback(url,i,this.result);
					}
				}
			};
			xhr.onreadystatechange = function(e) {
				if (this.readyState == 4 && this.status !== 200) {
					callback(url,i,false);
					return ;
				}
			};

			xhr.timeout = 3000;
			xhr.responseType = 'blob';
			xhr.open('get',url, true);
			xhr.send(null);
		};

		p.indexGet = function(url,callback){
			var request = p.init();
			if (request){
				request.onsuccess = function(e){
					var db = e.target.result;
					var transaction = db.transaction($.smConfig.indexedDB.storeName,'readwrite');
					var objStore = transaction.objectStore($.smConfig.indexedDB.storeName);
					var reslut = objStore.index('url').get(url);
					reslut.onsuccess=function(e){
						if (callback) callback(e.target.result,objStore);
					}
				};
				request.onerror = function(e){
					console.warn(e);
				}
			}
		};

		p.insert = function(url,data){
			data = $.extend({"timeStamp": new Date().getTime()},data);
			p.indexGet(url,function(result,objStore){
				if (result) data.timeStamp = result.timeStamp;
				objStore.put(data);
			});
		};

		p.delete = function(url){
			p.indexGet(url,function(result,objStore){
				if (result){
					objStore.delete(result.timeStamp);
				}
			});
		};

		//替换数据
		p.replace = function(url, content){
			var reg=/((http|https|ftp|):\/\/[\w\-_]+\.[\w\-_]+[\w\-\.,@?^=%&:/~\+#]*[\w\-\@?^=%&/~\+#]?.(jpg|jpeg|bmp|gif|png))/gi;
			var content = JSON.stringify(content),urls = content.match(reg);

			if (urls && urls.length){
				for (var i = 0; i < urls.length; i++) {
					this.imgToBase64(urls[i],i,function(imgUrl,i,result){
						if (result){
							content = content.replace(imgUrl,result);
						}
						if (i === urls.length - 1){
							p.insert(url,{url:url,content:JSON.parse(content)});
						}
					})
				}
			}else{
				p.insert(url,{url:url,content:JSON.parse(content)});
			}
		};
		return p;
	};

	$.storage = new storage();

}($);

//重置AJAX 加入队列功能
;(function($){
	var queueAjax = {
		zepAjax: $.ajax,
		requests: {}, // ajax对象集合
		globalPool: [], // 全局ajax程序池
		unglobalPool: [], // 非全局ajax程序池
		interval: null, // ajax循环定时器
		ajaxType: null, // 正在运行的Ajax类型  1:全局  2：非全局
		ajaxId: null,// 正在运行的AjaxId,

		pushPool: function (request, options) {
			var urlComplete = request.complete;
			var requests = this.requests;
			var id = (request.id) ? request.id : request.url;
			request.complete = this.del(urlComplete, id);

			var requestObj = {
				id: id,
				request: request,
				options: options
			};

			// 如果是获取json数据的请求，则放入程序池中，如果是获取Js或图片等资源的请求，则直接执行
			if (requestObj.request.dataType == 'json' ||
				requestObj.request.dataType == 'jsonp' ||
				requestObj.request.dataType == 'xml' ||
				requestObj.request.dataType == 'html' ||
				requestObj.request.dataType == 'text') {
				if (request.global) {
					// 如果是全局ajax
					this.globalPool.push(requestObj);
				} else {
					// 如果不是全局ajax
					this.unglobalPool.push(requestObj);
				}
			} else {
				queueAjax.run(requestObj);
			}

			if (!this.interval) {
				this.interval = window.setInterval(function () {

					// 如果当前有全局Ajax未运行，则停止正在运行的非全局Ajax
					if (queueAjax.ajaxType != 1 && queueAjax.globalPool.length > 0) {
						if (queueAjax.ajaxType == 2 && queueAjax.ajaxId) {
							queueAjax.abort(id);
						}

						// 运行最开头的全局Ajax
						var reqObj = queueAjax.globalPool.shift();
						queueAjax.run(reqObj);

					} else {
						// 如果当前没有正在执行的Ajax，并且非全局Ajax程序池中有对象
						if (queueAjax.ajaxType == null && queueAjax.unglobalPool.length > 0) {

							// 运行最开头的非全局Ajax
							var reqObj = queueAjax.unglobalPool.shift();
							queueAjax.run(reqObj);
						}
					}
				}, 100);
			}
		},
		del: function (urlComplete, id) {
			if (urlComplete && typeof (urlComplete) == "function") {
				urlComplete();
			}

			if (queueAjax.requests[id]) {
				delete queueAjax.requests[id];
			}

			// 如果程序池中已无请求，则清空ajax循环定时器
			if (queueAjax.globalPool.length <= 0 && queueAjax.unglobalPool.length <= 0) {
				queueAjax.interval = null;
			}

			// 如果当前请求结束，则重置正在运行的Ajax类型及AjaxId
			queueAjax.ajaxType = null;
			queueAjax.ajaxId = null;
		},

		run: function (reqObj) {

			var success = reqObj.request.success,
				url = reqObj.request.url,
				storage = reqObj.request.storage,
				onLine = navigator.onLine;
				url = url + (url.indexOf('?') >= 0 ? '&' : '?') + $.buildUrl(reqObj.request.data);

			//是否开启本地存储
			if (storage){
				//去除url值
				if ($.isArray(reqObj.request.storage)){
					$.each(reqObj.request.storage,function(i,value){
						url = $.removeUrl(url,value);
					});
				};



				reqObj.request.success = function(data){
					if (success) success(data);
					$.storage.replace(url,data);
				};
			}else if (reqObj.request.storage === false){
				//删除存储的数据
				$.storage.delete(url)
			}

			if (storage && !onLine){
				$.storage.indexGet(url,function(result){
					var content = result ?　result.content : '';
					success(content,'offline'); //标识离线
				});
				return ;
			}

			var jqXHR = this.zepAjax(reqObj.request, reqObj.options);
			this.requests[reqObj.id] = jqXHR;
		},
		abort: function (id) {
			var jqXHR = this.requests[id];
			if (jqXHR) {
				jqXHR.abort();
				delete this.requests[id];
			}
		}
	};
	$.ajax = function (param, options) {
		queueAjax.pushPool(param,options);
	}
})($);


;(function ($) {
    "use strict";
    var device = {};
    var ua = navigator.userAgent;

    var android = ua.match(/(Android);?[\s\/]+([\d.]+)?/);
    var ipad = ua.match(/(iPad).*OS\s([\d_]+)/);
    var ipod = ua.match(/(iPod)(.*OS\s([\d_]+))?/);
    var iphone = !ipad && ua.match(/(iPhone\sOS)\s([\d_]+)/);

    device.ios = device.android = device.iphone = device.ipad = device.androidChrome = false;

    // Android
    if (android) {
        device.os = 'android';
        device.osVersion = android[2];
        device.android = true;
        device.androidChrome = ua.toLowerCase().indexOf('chrome') >= 0;
    }
    if (ipad || iphone || ipod) {
        device.os = 'ios';
        device.ios = true;
    }
    // iOS
    if (iphone && !ipod) {
        device.osVersion = iphone[2].replace(/_/g, '.');
        device.iphone = true;
    }
    if (ipad) {
        device.osVersion = ipad[2].replace(/_/g, '.');
        device.ipad = true;
    }
    if (ipod) {
        device.osVersion = ipod[3] ? ipod[3].replace(/_/g, '.') : null;
        device.iphone = true;
    }
    // iOS 8+ changed UA
    if (device.ios && device.osVersion && ua.indexOf('Version/') >= 0) {
        if (device.osVersion.split('.')[0] === '10') {
            device.osVersion = ua.toLowerCase().split('version/')[1].split(' ')[0];
        }
    }

    // Webview
    device.webView = (iphone || ipad || ipod) && ua.match(/.*AppleWebKit(?!.*Safari)/i);

    // Minimal UI
    if (device.os && device.os === 'ios') {
        var osVersionArr = device.osVersion.split('.');
        device.minimalUi = !device.webView &&
            (ipod || iphone) &&
            (osVersionArr[0] * 1 === 7 ? osVersionArr[1] * 1 >= 1 : osVersionArr[0] * 1 > 7) &&
            $('meta[name="viewport"]').length > 0 && $('meta[name="viewport"]').attr('content').indexOf('minimal-ui') >= 0;
    }

    // Check for status bar and fullscreen app mode
    var windowWidth = $(window).width();
    var windowHeight = $(window).height();
    device.statusBar = false;
    if (device.webView && (windowWidth * windowHeight === screen.width * screen.height)) {
        device.statusBar = true;
    }
    else {
        device.statusBar = false;
    }

    // Classes
    var classNames = [];

    // Pixel Ratio
    device.pixelRatio = window.devicePixelRatio || 1;
    classNames.push('pixel-ratio-' + Math.floor(device.pixelRatio));
    if (device.pixelRatio >= 2) {
        classNames.push('retina');
    }

    // OS classes
    if (device.os) {
        classNames.push(device.os, device.os + '-' + device.osVersion.split('.')[0], device.os + '-' + device.osVersion.replace(/\./g, '-'));
        if (device.os === 'ios') {
            var major = parseInt(device.osVersion.split('.')[0], 10);
            for (var i = major - 1; i >= 6; i--) {
                classNames.push('ios-gt-' + i);
            }
        }

    }
    // Status bar classes
    if (device.statusBar) {
        classNames.push('with-statusbar-overlay');
    }
    else {
        $('html').removeClass('with-statusbar-overlay');
    }

    // Add html classes
    if (classNames.length > 0) $('html').addClass(classNames.join(' '));

    // keng..
    device.isWeixin = /MicroMessenger/i.test(ua);

    $.device = device;
})($);

;(function () {
    'use strict';
    function FastClick(layer, options) {
        var oldOnClick;
        options = options || {};
        this.trackingClick = false;
        this.trackingClickStart = 0;
        this.targetElement = null;
        this.touchStartX = 0;
        this.touchStartY = 0;
        this.lastTouchIdentifier = 0;
        this.touchBoundary = options.touchBoundary || 10;
        this.layer = layer;
        this.tapDelay = options.tapDelay || 200;

        this.tapTimeout = options.tapTimeout || 700;

        if (FastClick.notNeeded(layer)) {
            return;
        }

        function bind(method, context) {
            return function() { return method.apply(context, arguments); };
        }


        var methods = ['onMouse', 'onClick', 'onTouchStart', 'onTouchMove', 'onTouchEnd', 'onTouchCancel'];
        var context = this;
        for (var i = 0, l = methods.length; i < l; i++) {
            context[methods[i]] = bind(context[methods[i]], context);
        }

        // Set up event handlers as required
        if (deviceIsAndroid) {
            layer.addEventListener('mouseover', this.onMouse, true);
            layer.addEventListener('mousedown', this.onMouse, true);
            layer.addEventListener('mouseup', this.onMouse, true);
        }

        layer.addEventListener('click', this.onClick, true);
        layer.addEventListener('touchstart', this.onTouchStart, false);
        layer.addEventListener('touchmove', this.onTouchMove, false);
        layer.addEventListener('touchend', this.onTouchEnd, false);
        layer.addEventListener('touchcancel', this.onTouchCancel, false);


        if (!Event.prototype.stopImmediatePropagation) {
            layer.removeEventListener = function(type, callback, capture) {
                var rmv = Node.prototype.removeEventListener;
                if (type === 'click') {
                    rmv.call(layer, type, callback.hijacked || callback, capture);
                } else {
                    rmv.call(layer, type, callback, capture);
                }
            };

            layer.addEventListener = function(type, callback, capture) {
                var adv = Node.prototype.addEventListener;
                if (type === 'click') {
                    adv.call(layer, type, callback.hijacked || (callback.hijacked = function(event) {
                        if (!event.propagationStopped) {
                            callback(event);
                        }
                    }), capture);
                } else {
                    adv.call(layer, type, callback, capture);
                }
            };
        }

        if (typeof layer.onclick === 'function') {
            oldOnClick = layer.onclick;
            layer.addEventListener('click', function(event) {
                oldOnClick(event);
            }, false);
            layer.onclick = null;
        }
    }

    var deviceIsWindowsPhone = navigator.userAgent.indexOf("Windows Phone") >= 0;


    var deviceIsAndroid = navigator.userAgent.indexOf('Android') > 0 && !deviceIsWindowsPhone;

    var deviceIsIOS = /iP(ad|hone|od)/.test(navigator.userAgent) && !deviceIsWindowsPhone;

    var deviceIsIOS4 = deviceIsIOS && (/OS 4_\d(_\d)?/).test(navigator.userAgent);

    var deviceIsIOSWithBadTarget = deviceIsIOS && (/OS [6-7]_\d/).test(navigator.userAgent);

    var deviceIsBlackBerry10 = navigator.userAgent.indexOf('BB10') > 0;

    var isCompositeLabel = false;

    FastClick.prototype.needsClick = function(target) {

        // 修复bug: 如果父元素中有 label
        // 如果label上有needsclick这个类，则用原生的点击，否则，用模拟点击
        var parent = target;
        while(parent && (parent.tagName.toUpperCase() !== "BODY")) {
            if (parent.tagName.toUpperCase() === "LABEL") {
                isCompositeLabel = true;
                if ((/\bneedsclick\b/).test(parent.className)) return true;
            }
            parent = parent.parentNode;
        }

        switch (target.nodeName.toLowerCase()) {
            case 'button':
            case 'select':
            case 'textarea':
                if (target.disabled){
					return true;
                }
                break;
            case 'input':
                if ((deviceIsIOS && target.type === 'file') || target.disabled) {
                    return true;
                }
                break;
            case 'label':
            case 'iframe':
            case 'video':
                return true;
        }
        return (/\bneedsclick\b/).test(target.className);
    };

    FastClick.prototype.needsFocus = function(target) {
        switch (target.nodeName.toLowerCase()) {
            case 'textarea':
                return true;
            case 'select':
                return !deviceIsAndroid;
            case 'input':
                switch (target.type) {
                    case 'button':
                    case 'checkbox':
                    case 'file':
                    case 'image':
                    case 'radio':
                    case 'submit':
                        return false;
                }

                // No point in attempting to focus disabled inputs
                return !target.disabled && !target.readOnly;
            default:
                return (/\bneedsfocus\b/).test(target.className);
        }
    };

    FastClick.prototype.sendClick = function(targetElement, event) {
        var clickEvent, touch;

        // On some Android devices activeElement needs to be blurred otherwise the synthetic click will have no effect (#24)
        if (document.activeElement && document.activeElement !== targetElement) {
            document.activeElement.blur();
        }

        touch = event.changedTouches[0];

        // Synthesise a click event, with an extra attribute so it can be tracked
        clickEvent = document.createEvent('MouseEvents');
        clickEvent.initMouseEvent(this.determineEventType(targetElement), true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0, null);
        clickEvent.forwardedTouchEvent = true;
        targetElement.dispatchEvent(clickEvent);
    };

    FastClick.prototype.determineEventType = function(targetElement) {

        //Issue #159: Android Chrome Select Box does not open with a synthetic click event
        if (deviceIsAndroid && targetElement.tagName.toLowerCase() === 'select') {
            return 'mousedown';
        }

        return 'click';
    };

    FastClick.prototype.focus = function(targetElement) {
        var length;

        // Issue #160: on iOS 7, some input elements (e.g. date datetime month) throw a vague TypeError on setSelectionRange. These elements don't have an integer value for the selectionStart and selectionEnd properties, but unfortunately that can't be used for detection because accessing the properties also throws a TypeError. Just check the type instead. Filed as Apple bug #15122724.
        var unsupportedType = ['date', 'time', 'month', 'number', 'email'];
        if (deviceIsIOS && targetElement.setSelectionRange && unsupportedType.indexOf(targetElement.type) === -1) {
            length = targetElement.value.length;
            targetElement.setSelectionRange(length, length);
        } else {
            targetElement.focus();
        }
    };


    FastClick.prototype.updateScrollParent = function(targetElement) {
        var scrollParent, parentElement;

        scrollParent = targetElement.fastClickScrollParent;

        // Attempt to discover whether the target element is contained within a scrollable layer. Re-check if the
        // target element was moved to another parent.
        if (!scrollParent || !scrollParent.contains(targetElement)) {
            parentElement = targetElement;
            do {
                if (parentElement.scrollHeight > parentElement.offsetHeight) {
                    scrollParent = parentElement;
                    targetElement.fastClickScrollParent = parentElement;
                    break;
                }

                parentElement = parentElement.parentElement;
            } while (parentElement);
        }

        // Always update the scroll top tracker if possible.
        if (scrollParent) {
            scrollParent.fastClickLastScrollTop = scrollParent.scrollTop;
        }
    };


    FastClick.prototype.getTargetElementFromEventTarget = function(eventTarget) {

        // On some older browsers (notably Safari on iOS 4.1 - see issue #56) the event target may be a text node.
        if (eventTarget.nodeType === Node.TEXT_NODE) {
            return eventTarget.parentNode;
        }

        return eventTarget;
    };

    FastClick.prototype.onTouchStart = function(event) {
        var targetElement, touch, selection;

        // Ignore multiple touches, otherwise pinch-to-zoom is prevented if both fingers are on the FastClick element (issue #111).
        if (event.targetTouches.length > 1) {
            return true;
        }

        targetElement = this.getTargetElementFromEventTarget(event.target);
        touch = event.targetTouches[0];

        if (deviceIsIOS) {

            // Only trusted events will deselect text on iOS (issue #49)
            selection = window.getSelection();
            if (selection.rangeCount && !selection.isCollapsed) {
                return true;
            }

            if (!deviceIsIOS4) {
                   if (touch.identifier && touch.identifier === this.lastTouchIdentifier) {
                    event.preventDefault();
                    return false;
                }

                this.lastTouchIdentifier = touch.identifier;
                this.updateScrollParent(targetElement);
            }
        }

        this.trackingClick = true;
        this.trackingClickStart = event.timeStamp;
        this.targetElement = targetElement;

        this.touchStartX = touch.pageX;
        this.touchStartY = touch.pageY;

        // Prevent phantom clicks on fast double-tap (issue #36)
        if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
            event.preventDefault();
        }

        return true;
    };

    FastClick.prototype.touchHasMoved = function(event) {
        var touch = event.changedTouches[0], boundary = this.touchBoundary;

        if (Math.abs(touch.pageX - this.touchStartX) > boundary || Math.abs(touch.pageY - this.touchStartY) > boundary) {
            return true;
        }

        return false;
    };


    FastClick.prototype.onTouchMove = function(event) {
        if (!this.trackingClick) {
            return true;
        }

        // If the touch has moved, cancel the click tracking
        if (this.targetElement !== this.getTargetElementFromEventTarget(event.target) || this.touchHasMoved(event)) {
            this.trackingClick = false;
            this.targetElement = null;
        }

        return true;
    };

    FastClick.prototype.findControl = function(labelElement) {

        // Fast path for newer browsers supporting the HTML5 control attribute
        if (labelElement.control !== undefined) {
            return labelElement.control;
        }

        // All browsers under test that support touch events also support the HTML5 htmlFor attribute
        if (labelElement.htmlFor) {
            return document.getElementById(labelElement.htmlFor);
        }

        // If no for attribute exists, attempt to retrieve the first labellable descendant element
        // the list of which is defined here: http://www.w3.org/TR/html5/forms.html#category-label
        return labelElement.querySelector('button, input:not([type=hidden]), keygen, meter, output, progress, select, textarea');
    };

    FastClick.prototype.onTouchEnd = function(event) {
        var forElement, trackingClickStart, targetTagName, scrollParent, touch, targetElement = this.targetElement;

        if (!this.trackingClick) {
            return true;
        }

        // Prevent phantom clicks on fast double-tap (issue #36)
        if ((event.timeStamp - this.lastClickTime) < this.tapDelay) {
            this.cancelNextClick = true;
            return true;
        }

        if ((event.timeStamp - this.trackingClickStart) > this.tapTimeout) {
            return true;
        }
        //修复安卓微信下，input type="date" 的bug，经测试date,time,month已没问题
        var unsupportedType = ['date', 'time', 'month'];
        if(unsupportedType.indexOf(event.target.type) !== -1){
            　　　　return false;
            　　}
        // Reset to prevent wrong click cancel on input (issue #156).
        this.cancelNextClick = false;

        this.lastClickTime = event.timeStamp;

        trackingClickStart = this.trackingClickStart;
        this.trackingClick = false;
        this.trackingClickStart = 0;
        if (deviceIsIOSWithBadTarget) {
            touch = event.changedTouches[0];

            targetElement = document.elementFromPoint(touch.pageX - window.pageXOffset, touch.pageY - window.pageYOffset) || targetElement;
            targetElement.fastClickScrollParent = this.targetElement.fastClickScrollParent;
        }

        targetTagName = targetElement.tagName.toLowerCase();
        if (targetTagName === 'label') {
            forElement = this.findControl(targetElement);
            if (forElement) {
                this.focus(targetElement);
                if (deviceIsAndroid) {
                    return false;
                }

                targetElement = forElement;
            }
        } else if (this.needsFocus(targetElement)) {
            if ((event.timeStamp - trackingClickStart) > 100 || (deviceIsIOS && window.top !== window && targetTagName === 'input')) {
                this.targetElement = null;
                return false;
            }

            this.focus(targetElement);
            this.sendClick(targetElement, event);
            if (!deviceIsIOS || targetTagName !== 'select') {
                this.targetElement = null;
                event.preventDefault();
            }

            return false;
        }

        if (deviceIsIOS && !deviceIsIOS4) {

            scrollParent = targetElement.fastClickScrollParent;
            if (scrollParent && scrollParent.fastClickLastScrollTop !== scrollParent.scrollTop) {
                return true;
            }
        }
        if (!this.needsClick(targetElement)) {
            event.preventDefault();
            this.sendClick(targetElement, event);
        }

        return false;
    };


    FastClick.prototype.onTouchCancel = function() {
        this.trackingClick = false;
        this.targetElement = null;
    };


    FastClick.prototype.onMouse = function(event) {

        // If a target element was never set (because a touch event was never fired) allow the event
        if (!this.targetElement) {
            return true;
        }

        if (event.forwardedTouchEvent) {
            return true;
        }

        // Programmatically generated events targeting a specific element should be permitted
        if (!event.cancelable) {
            return true;
        }

        if (!this.needsClick(this.targetElement) || this.cancelNextClick) {

            // Prevent any user-added listeners declared on FastClick element from being fired.
            if (event.stopImmediatePropagation) {
                event.stopImmediatePropagation();
            } else {

                // Part of the hack for browsers that don't support Event#stopImmediatePropagation (e.g. Android 2)
                event.propagationStopped = true;
            }

            // Cancel the event
            event.stopPropagation();
            // 允许组合型label冒泡
            if (!isCompositeLabel) {
                event.preventDefault();
            }
            // 允许组合型label冒泡
            return false;
        }

        // If the mouse event is permitted, return true for the action to go through.
        return true;
    };

  FastClick.prototype.onClick = function(event) {
        var permitted;

        // It's possible for another FastClick-like library delivered with third-party code to fire a click event before FastClick does (issue #44). In that case, set the click-tracking flag back to false and return early. This will cause onTouchEnd to return early.
        if (this.trackingClick) {
            this.targetElement = null;
            this.trackingClick = false;
            return true;
        }

        // Very odd behaviour on iOS (issue #18): if a submit element is present inside a form and the user hits enter in the iOS simulator or clicks the Go button on the pop-up OS keyboard the a kind of 'fake' click event will be triggered with the submit-type input element as the target.
        if (event.target.type === 'submit' && event.detail === 0) {
            return true;
        }

        permitted = this.onMouse(event);

        // Only unset targetElement if the click is not permitted. This will ensure that the check for !targetElement in onMouse fails and the browser's click doesn't go through.
        if (!permitted) {
            this.targetElement = null;
        }

        // If clicks are permitted, return true for the action to go through.
        return permitted;
    };


    FastClick.prototype.destroy = function() {
        var layer = this.layer;

        if (deviceIsAndroid) {
            layer.removeEventListener('mouseover', this.onMouse, true);
            layer.removeEventListener('mousedown', this.onMouse, true);
            layer.removeEventListener('mouseup', this.onMouse, true);
        }

        layer.removeEventListener('click', this.onClick, true);
        layer.removeEventListener('touchstart', this.onTouchStart, false);
        layer.removeEventListener('touchmove', this.onTouchMove, false);
        layer.removeEventListener('touchend', this.onTouchEnd, false);
        layer.removeEventListener('touchcancel', this.onTouchCancel, false);
    };


    FastClick.notNeeded = function(layer) {
        var metaViewport;
        var chromeVersion;
        var blackberryVersion;
        var firefoxVersion;

        // Devices that don't support touch don't need FastClick
        if (typeof window.ontouchstart === 'undefined') {
            return true;
        }

        // Chrome version - zero for other browsers
        chromeVersion = +(/Chrome\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];

        if (chromeVersion) {

            if (deviceIsAndroid) {
                metaViewport = document.querySelector('meta[name=viewport]');

                if (metaViewport) {
                    // Chrome on Android with user-scalable="no" doesn't need FastClick (issue #89)
                    if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
                        return true;
                    }
                    // Chrome 32 and above with width=device-width or less don't need FastClick
                    if (chromeVersion > 31 && document.documentElement.scrollWidth <= window.outerWidth) {
                        return true;
                    }
                }

                // Chrome desktop doesn't need FastClick (issue #15)
            } else {
                return true;
            }
        }

        if (deviceIsBlackBerry10) {
            blackberryVersion = navigator.userAgent.match(/Version\/([0-9]*)\.([0-9]*)/);

            // BlackBerry 10.3+ does not require Fastclick library.
            // https://github.com/ftlabs/fastclick/issues/251
            if (blackberryVersion[1] >= 10 && blackberryVersion[2] >= 3) {
                metaViewport = document.querySelector('meta[name=viewport]');

                if (metaViewport) {
                    // user-scalable=no eliminates click delay.
                    if (metaViewport.content.indexOf('user-scalable=no') !== -1) {
                        return true;
                    }
                    // width=device-width (or less than device-width) eliminates click delay.
                    if (document.documentElement.scrollWidth <= window.outerWidth) {
                        return true;
                    }
                }
            }
        }

        // IE10 with -ms-touch-action: none or manipulation, which disables double-tap-to-zoom (issue #97)
        if (layer.style.msTouchAction === 'none' || layer.style.touchAction === 'manipulation') {
            return true;
        }

        // Firefox version - zero for other browsers
        firefoxVersion = +(/Firefox\/([0-9]+)/.exec(navigator.userAgent) || [,0])[1];

        if (firefoxVersion >= 27) {
            // Firefox 27+ does not have tap delay if the content is not zoomable - https://bugzilla.mozilla.org/show_bug.cgi?id=922896

            metaViewport = document.querySelector('meta[name=viewport]');
            if (metaViewport && (metaViewport.content.indexOf('user-scalable=no') !== -1 || document.documentElement.scrollWidth <= window.outerWidth)) {
                return true;
            }
        }

        // IE11: prefixed -ms-touch-action is no longer supported and it's recomended to use non-prefixed version
        // http://msdn.microsoft.com/en-us/library/windows/apps/Hh767313.aspx
        if (layer.style.touchAction === 'none' || layer.style.touchAction === 'manipulation') {
            return true;
        }

        return false;
    };

    FastClick.attach = function(layer, options) {
        return new FastClick(layer, options);
    };

    window.FastClick = FastClick;
}());

/*
* 模板引擎
*/
+function($){
	"use strict";
 $.template = {
	//渲染模板
    render : function(id, data, options){
      data = data || this.data;
      var elm = $(id), fn, html;
      if(elm.length>0){
        if(id in this.cache){
          fn = this.cache[id];
        }else{
          fn = this.cache[id] = this.compile(elm.html(), '', options);
        }
        try{
          html = fn(data);
        }catch(e){
          html = $.template.error(e,id, 'Render');
        }
        if(elm[0]['tagName'].toUpperCase() !== 'SCRIPT'){
          html = html.replace(/<[^>]+>/g, function(a){
            return a.replace(/\btpl:/ig,'');//替换tpl虚构标签
          });
          elm.html(html);
          elm.attr('type','text/x-template');
        }
      }else if(id.indexOf('.') !== -1){
		//ajax同步引入模板文件
        var _this = this;
        $.ajax({
			async: false,
			url:id,
			success: function(dataStr){
				html = _this.compile(dataStr, data, options);
			}
        });
      }else{
		console.warn('Template cannot find \''+ id +'\'');
      }

	  return html;
    },
	//编译字符串
    compile : function(str, data, options){
      var rep = this.__proto__?
        ["var s='';", "s+='", "';", "'+(", ")+'", "return s;"]:
        ["var s=[];", "s.push('", "');", "',", ",'", "return s.join('');"];
      var o = options || {};
      var _this = this;
      var _left = o.leftTag || this.config.leftTag;
      var _right = o.rightTag || this.config.rightTag;
      var escape = o.escape || this.config.escape;
      var _l = _left.replace('<','&lt;');
      var _r = _right.replace('>','&gt;');
          str = str.split(_l).join(_left).split(_r).join(_right);

      var varString = [];
      var fnBody = rep[0] + rep[1] +
        str
        .replace(/[\r\t\n]/g, "")
        .split(_left).join("\t")
        .split(_right).join("\r")
        .replace(/((^|\r)([^\t]*))/g, function(a,b,c,d){//html处理
          return c + d.replace(/('|\\)/g, '\\$1');
        })
        .replace(/(\t)(.*?)(\r)/g, function(a,b,c){//code处理
		c = c.replace(/&amp;/g,'&')
		.replace(/&lt;/g,'<')
		.replace(/&gt;/g,'>');

          return _this.parsing(c, varString, rep, escape);
        }) +
        rep[2] + rep[5];
      fnBody = varString.join('') + fnBody;
      if(o.debug){
        console.log('Template HTML:' + str);
        console.log('Template Render:\nfunction(data){' + fnBody + '}');
      }
      try{
        var fn = new Function('data', fnBody);
        return data? fn(data): fn;
      }catch(e){
        var eMsg = $.template.error(e, str, 'Compile');
        return function(){
          return eMsg;
        };
      }
    },
	//编译语法
    parsing : function(code, varString, rep, escape){
      var codeArr = code.replace(/^\s*|\s*$/g,'').replace(/\s{2,}/g,' ').split(' ');//处理多余空格后分组
      var varArr = /\$(\w+)/g.exec(code);
      if(varArr && !varString[varArr[1]]){//储存变量
        varString.push('var $',varArr[1],'=data.',varArr[1],';');
        varString[varArr[1]] = true;
      }
      switch(codeArr[0]){
        case 'if':
          return rep[2] + 'if('+ code.slice(3) +'){' + rep[1];
        case 'else':
          return rep[2] + '}else{' + rep[1];
        case 'elseif':
          return rep[2] + '}else if('+ code.slice(7) +'){' + rep[1];
        case '/if':
          return rep[2] + '}' + rep[1];
        case 'foreach':
          var e_o = codeArr[1];
          var e_p = codeArr[3] || '$item';
          var e_i = (codeArr[2] === 'as'? codeArr[4]: codeArr[2]) || '$index';
          return rep[2] + '$.template.foreach('+ e_o +',function('+ e_p +','+ e_i +'){' + rep[1];
        case '/foreach':
          return rep[2] + '});' + rep[1];
        case 'include':
          return rep[3] + '$.template.render('+ codeArr.slice(1).join('') +')' + rep[4];
        default://输出变量
          if(/[^|]\|[^|]/.test(code)){//helpers
            code = $.template.filter(code);
          }
          return rep[3] + (escape?'$.template.escape(String('+ code +'))' : code) + rep[4];
      }
    },
    filter: function(code){
      var arr = code.split('|');
      var str = arr[0];
      var len = arr.length;
      for(var i = 1; i < len; i++){
        var fnArr = arr[i].replace(/^\s+/, '').split(' ');
        var fnName = fnArr.shift();
        var args = fnArr.join(' ');
        args = args? ', ' + args : args;
        str = '$.template.helpers.' + fnName + '(' + str + args + ')';
      }
      return str;
	},
	//HTML转义
    escape : function(str){
      return str
          .replace(/&/g,'&amp;')
          .replace(/</g,'&lt;')
          .replace(/>/g,'&gt;')
          .replace(/"/g,'&quot;')
          .replace(/'/g,'&#39;');
    },
    foreach : function(data, callback){//遍历对象
      if (({}).toString.call(data) === '[object Array]') {
          for (var i = 0, len = data.length; i < len; i++) {
              callback.call(data[i], data[i], i);
          }
      } else {
          for (var p in data) {
              callback.call(data[p], data[p], p);
          }
      }
    },
    helpers: {
      escape: function(str){
        return $.template.escape(String(str));
      }
    },
    error: function(e, id, type){
      var pos = id.length > 100? id.slice(0, 100)+ '...': id;
      var eMsg = 'Template '+ type +' Error: ' + e.message + ' in \'' + pos +'\'';
      console.error(eMsg);
      return eMsg;
    },
    cache : {},//模板函数缓存
    data : {},//模板全局数据缓存
    config: {//模板全局配置
      leftTag : '{',//语法左分隔符
      rightTag : '}',//语法左右隔符
      escape : false//模板输出的变量是否HTML转义
    }
  };

}($);


+function($) {
	$.formToJSON = function (form) {
		form = $(form);
		if (form.length !== 1) return false;
		var formData = {};
		var skipTypes = ['submit', 'image', 'button', 'file'];
		var skipNames = [];
		form.find('input, select, textarea').each(function () {
			var input = $(this);
			var name = input.attr('name');
			var type = input.attr('type');
			var tag = this.nodeName.toLowerCase();
			if (skipTypes.indexOf(type) >= 0) return;
			if (skipNames.indexOf(name) >= 0 || !name) return;
			if (tag === 'select' && input.attr('multiple')) {
				skipNames.push(name);
				formData[name] = [];
				form.find('select[name="' + name + '"] option').each(function () {
					if (this.selected) formData[name].push(this.value);
				});
			}
			else {
				switch (type) {
					case 'checkbox' :
						skipNames.push(name);
						formData[name] = [];
						form.find('input[name="' + name + '"]').each(function () {
							if (this.checked) formData[name].push(this.value);
						});
						break;
					case 'radio' :
						skipNames.push(name);
						form.find('input[name="' + name + '"]').each(function () {
							if (this.checked) formData[name] = this.value;
						});
						break;
					default :
						formData[name] = input.val();
						break;
				}
			}

		});
		form.trigger('formToJSON', {formData: formData});
		return formData;
	};

	 $.formFromJSON = function (form, formData) {
		form = $(form);
		if (form.length !== 1) return false;
		var skipTypes = ['submit', 'image', 'button', 'file'];
		var skipNames = [];
		form.find('input, select, textarea').each(function () {
			var input = $(this);
			var name = input.attr('name');
			var type = input.attr('type');
			var tag = this.nodeName.toLowerCase();
			if (!formData[name]) return;
			if (skipTypes.indexOf(type) >= 0) return;
			if (skipNames.indexOf(name) >= 0 || !name) return;
			if (tag === 'select' && input.attr('multiple')) {
				skipNames.push(name);
				form.find('select[name="' + name + '"] option').each(function () {
					if (formData[name].indexOf(this.value) >= 0) this.selected = true;
					else this.selected = false;
				});
			}
			else {
				switch (type) {
					case 'checkbox' :
						skipNames.push(name);
						form.find('input[name="' + name + '"]').each(function () {
							if (formData[name].indexOf(this.value) >= 0) this.checked = true;
							else this.checked = false;
						});
						break;
					case 'radio' :
						skipNames.push(name);
						form.find('input[name="' + name + '"]').each(function () {
							if (formData[name] === this.value) this.checked = true;
							else this.checked = false;
						});
						break;
					default :
						input.val(formData[name]);
						break;
				}
			}

		});
		form.trigger('formFromJSON', {formData: formData});
	};

	$(document).on('submit change', 'form.ajax-submit, form.ajax-submit-onchange', function (e) {
		var $form = $(this);
		if (e.type === 'change' && !$form.hasClass('ajax-submit-onchange')) return;
		if (e.type === 'submit') e.preventDefault();

		var method = $form.attr('method') || 'GET';
		var contentType = $form.prop('enctype') || $form.attr('enctype');

		var url = $form.attr('action');
		if (!url) return;

		var data;
		if (method === 'POST') data = new FormData($form[0]);
		else data = $.serializeObject($.formToJSON($form[0]));

		var xhr = $.ajax({
			method: method,
			url: url,
			storage:false,
			contentType: contentType,
			data: data,
			beforeSend: function (xhr) {
				$form.trigger('beforeSubmit', {data:data, xhr: xhr});
			},
			error: function (xhr) {
				$form.trigger('submitError', {data:data, xhr: xhr});
			},
			success: function (data) {
				$form.trigger('submitted', {data: data, xhr: xhr});
			}
		});
	});

}($);


+function ($) {
    "use strict";
    var _modalTemplateTempDiv = document.createElement('div');

    $.modalStack = [];

    $.modalStackClearQueue = function () {
        if ($.modalStack.length) {
            ($.modalStack.shift())();
        }
    };

    $.modal = function (params) {
        params = params || {};
        var modalHTML = '';
        var buttonsHTML = '';
        if (params.buttons && params.buttons.length > 0) {
            for (var i = 0; i < params.buttons.length; i++) {
                buttonsHTML += '<span class="modal-button' + (params.buttons[i].bold ? ' modal-button-bold' : '') + '">' + params.buttons[i].text + '</span>';
            }
        }
        var extraClass = params.extraClass || '';
        var titleHTML = params.title ? '<div class="modal-title">' + params.title + '</div>' : '';
        var textHTML = params.text ? '<div class="modal-text">' + params.text + '</div>' : '';
        var afterTextHTML = params.afterText ? params.afterText : '';
        var noButtons = !params.buttons || params.buttons.length === 0 ? 'modal-no-buttons' : '';
        var verticalButtons = params.verticalButtons ? 'modal-buttons-vertical' : '';
        modalHTML = '<div class="modal ' + extraClass + ' ' + noButtons + '"><div class="modal-inner">' + (titleHTML + textHTML + afterTextHTML) + '</div><div class="modal-buttons ' + verticalButtons + '">' + buttonsHTML + '</div></div>';

        _modalTemplateTempDiv.innerHTML = modalHTML;

        var modal = $(_modalTemplateTempDiv).children();

        $(defaults.modalContainer).append(modal[0]);

        // Add events on buttons
        modal.find('.modal-button').each(function (index, el) {
            $(el).on('click', function (e) {
                if (params.buttons[index].close !== false) $.closeModal(modal);
                if (params.buttons[index].onClick) params.buttons[index].onClick(modal, e);
                if (params.onClick) params.onClick(modal, index);
            });
        });
        $.openModal(modal);
        return modal[0];
    };
    $.alert = function (text, title, callbackOk) {
        if (typeof title === 'function') {
            callbackOk = arguments[1];
            title = undefined;
        }
        return $.modal({
            text: text || '',
            title: typeof title === 'undefined' ? defaults.modalTitle : title,
            buttons: [ {text: defaults.modalButtonOk, bold: true, onClick: callbackOk} ]
        });
    };
    $.confirm = function (text, title, callbackOk, callbackCancel) {
        if (typeof title === 'function') {
            callbackCancel = arguments[2];
            callbackOk = arguments[1];
            title = undefined;
        }
        return $.modal({
            text: text || '',
            title: typeof title === 'undefined' ? defaults.modalTitle : title,
            buttons: [
                {text: defaults.modalButtonCancel, onClick: callbackCancel},
                {text: defaults.modalButtonOk, bold: true, onClick: callbackOk}
            ]
        });
    };
    $.prompt = function (text, title, callbackOk, callbackCancel) {
        if (typeof title === 'function') {
            callbackCancel = arguments[2];
            callbackOk = arguments[1];
            title = undefined;
        }
        return $.modal({
            text: text || '',
            title: typeof title === 'undefined' ? defaults.modalTitle : title,
            afterText: '<input type="text" class="modal-text-input">',
            buttons: [
                {
                    text: defaults.modalButtonCancel
                },
                {
                    text: defaults.modalButtonOk,
                    bold: true
                }
            ],
            onClick: function (modal, index) {
                if (index === 0 && callbackCancel) callbackCancel($(modal).find('.modal-text-input').val());
                if (index === 1 && callbackOk) callbackOk($(modal).find('.modal-text-input').val());
            }
        });
    };

    $.showPreloader = function (title) {
        $.hidePreloader();
        $.showPreloader.preloaderModal = $.modal({
            title: title || defaults.modalPreloaderTitle,
            text: '<div class="preloader"></div>'
        });

        return $.showPreloader.preloaderModal;
    };

    $.hidePreloader = function () {
        $.showPreloader.preloaderModal && $.closeModal($.showPreloader.preloaderModal);
    };

    $.showIndicator = function () {
        if ($('.preloader-indicator-modal')[0]) return;
        $(defaults.modalContainer).append('<div class="preloader-indicator-overlay"></div><div class="preloader-indicator-modal"><span class="preloader preloader-white"></span></div>');
    };

    $.hideIndicator = function () {
        $('.preloader-indicator-overlay, .preloader-indicator-modal').remove();
    };

    $.actions = function (params) {
        var modal, groupSelector, buttonSelector;
        params = params || [];
        if (params.length > 0 && !$.isArray(params[0])) {
            params = [params];
        }

        var modalHTML;
		var buttonsHTML = '';
		for (var i = 0; i < params.length; i++) {
			for (var j = 0; j < params[i].length; j++) {
				if (j === 0) buttonsHTML += '<div class="actions-modal-group">';
				var button = params[i][j];
				var buttonClass = button.label ? 'actions-modal-label' : 'actions-modal-button';
				if (button.bold) buttonClass += ' actions-modal-button-bold';
				if (button.color) buttonClass += ' color-' + button.color;
				if (button.bg) buttonClass += ' bg-' + button.bg;
				if (button.disabled) buttonClass += ' disabled';
				buttonsHTML += '<span class="' + buttonClass + '">' + button.text + '</span>';
				if (j === params[i].length - 1) buttonsHTML += '</div>';
			}
		}
		modalHTML = '<div class="actions-modal">' + buttonsHTML + '</div>';
		_modalTemplateTempDiv.innerHTML = modalHTML;
		modal = $(_modalTemplateTempDiv).children();
		$(defaults.modalContainer).append(modal[0]);
		groupSelector = '.actions-modal-group';
		buttonSelector = '.actions-modal-button';

        var groups = modal.find(groupSelector);
        groups.each(function (index, el) {
            var groupIndex = index;
            $(el).children().each(function (index, el) {
                var buttonIndex = index;
                var buttonParams = params[groupIndex][buttonIndex];
                var clickTarget;
				if (!toPopover && $(el).is(buttonSelector)) clickTarget = $(el);
                if (toPopover && $(el).find(buttonSelector).length > 0) clickTarget = $(el).find(buttonSelector);

                if (clickTarget) {
                    clickTarget.on('click', function (e) {
                        if (buttonParams.close !== false) $.closeModal(modal);
                        if (buttonParams.onClick) buttonParams.onClick(modal, e);
                    });
                }
            });
        });
        $.openModal(modal);
        return modal[0];
    };

	$.popover = function (modal, target, removeOnClose) {
        if (typeof removeOnClose === 'undefined') removeOnClose = true;
        if (typeof modal === 'string' && modal.indexOf('<') >= 0) {
            var _modal = document.createElement('div');
            _modal.innerHTML = modal.trim();
            if (_modal.childNodes.length > 0) {
                modal = _modal.childNodes[0];
                if (removeOnClose) modal.classList.add('remove-on-close');
                $(defaults.modalContainer).append(modal);
            }
            else return false;
        }
        modal = $(modal);
        target = $(target);
        if (modal.length === 0 || target.length === 0) return false;
        if (modal.find('.popover-angle').length === 0) {
            modal.append('<div class="popover-angle"></div>');
        }
        modal.show();

        function sizePopover() {
            modal.css({left: '', top: ''});
            var modalWidth =  modal.width();
            var modalHeight =  modal.height();
            var modalAngle = modal.find('.popover-angle');
            var modalAngleSize = modalAngle.width() / 2;
            var modalAngleLeft, modalAngleTop;
            modalAngle.removeClass('on-left on-right on-top on-bottom').css({left: '', top: ''});

            var targetWidth = target.outerWidth();
            var targetHeight = target.outerHeight();
            var targetOffset = target.offset();
            var targetParentPage = target.parents('.page');
            if (targetParentPage.length > 0) {
                targetOffset.top = targetOffset.top - targetParentPage[0].scrollTop;
            }

            var windowHeight = $(window).height();
            var windowWidth = $(window).width();

            var modalTop = 0;
            var modalLeft = 0;
            var diff = 0;
            var modalPosition = 'top';

            if ((modalHeight + modalAngleSize) < targetOffset.top) {
                // On top
                modalTop = targetOffset.top - modalHeight - modalAngleSize;
            }
            else if ((modalHeight + modalAngleSize) < windowHeight - targetOffset.top - targetHeight) {
                // On bottom
                modalPosition = 'bottom';
                modalTop = targetOffset.top + targetHeight + modalAngleSize;
            }
            else {
                // On middle
                modalPosition = 'middle';
                modalTop = targetHeight / 2 + targetOffset.top - modalHeight / 2;
                diff = modalTop;
                if (modalTop < 0) {
                    modalTop = 5;
                }
                else if (modalTop + modalHeight > windowHeight) {
                    modalTop = windowHeight - modalHeight - 5;
                }
                diff = diff - modalTop;
            }
            // Horizontal Position
            if (modalPosition === 'top' || modalPosition === 'bottom') {
                modalLeft = targetWidth / 2 + targetOffset.left - modalWidth / 2;
                diff = modalLeft;
                if (modalLeft < 5) modalLeft = 5;
                if (modalLeft + modalWidth > windowWidth) modalLeft = windowWidth - modalWidth - 5;
                if (modalPosition === 'top') modalAngle.addClass('on-bottom');
                if (modalPosition === 'bottom') modalAngle.addClass('on-top');
                diff = diff - modalLeft;
                modalAngleLeft = (modalWidth / 2 - modalAngleSize + diff);
                modalAngleLeft = Math.max(Math.min(modalAngleLeft, modalWidth - modalAngleSize * 2 - 6), 6);
                modalAngle.css({left: modalAngleLeft + 'px'});
            }
            else if (modalPosition === 'middle') {
                modalLeft = targetOffset.left - modalWidth - modalAngleSize;
                modalAngle.addClass('on-right');
                if (modalLeft < 5) {
                    modalLeft = targetOffset.left + targetWidth + modalAngleSize;
                    modalAngle.removeClass('on-right').addClass('on-left');
                }
                if (modalLeft + modalWidth > windowWidth) {
                    modalLeft = windowWidth - modalWidth - 5;
                    modalAngle.removeClass('on-right').addClass('on-left');
                }
                modalAngleTop = (modalHeight / 2 - modalAngleSize + diff);
                modalAngleTop = Math.max(Math.min(modalAngleTop, modalHeight - modalAngleSize * 2 - 6), 6);
                modalAngle.css({top: modalAngleTop + 'px'});
            }

            // Apply Styles
            modal.css({top: modalTop + 'px', left: modalLeft + 'px'});
        }
        sizePopover();

        $(window).on('resize', sizePopover);
        modal.on('close', function () {
            $(window).off('resize', sizePopover);
        });

        if (modal.find('.' + defaults.viewClass).length > 0) {
            $.sizeNavbars(modal.find('.' + defaults.viewClass)[0]);
        }

        $.openModal(modal);
        return modal[0];
    };

    $.popup = function (modal, removeOnClose,callback) {
        if (typeof removeOnClose === 'undefined') removeOnClose = true;
        if (typeof modal === 'string' && modal.indexOf('<') >= 0) {
            var _modal = document.createElement('div');
            _modal.innerHTML = modal.trim();
            if (_modal.childNodes.length > 0) {
                modal = _modal.childNodes[0];
                if (removeOnClose) modal.classList.add('remove-on-close');
                $(defaults.modalContainer).append(modal);
            }
            else return false; //nothing found
        }
        modal = $(modal);
        if (modal.length === 0) return false;
        modal.show();
       // modal.find(".page-content").scroller("refresh");
        if (modal.find('.' + defaults.viewClass).length > 0) {
            $.sizeNavbars(modal.find('.' + defaults.viewClass)[0]);
        }
        $.openModal(modal,callback);

        return modal[0];
    };
    $.pickerModal = function (pickerModal, removeOnClose) {
        if (typeof removeOnClose === 'undefined') removeOnClose = true;
        if (typeof pickerModal === 'string' && pickerModal.indexOf('<') >= 0) {
            pickerModal = $(pickerModal);
            if (pickerModal.length > 0) {
                if (removeOnClose) pickerModal.addClass('remove-on-close');
                $(defaults.modalContainer).append(pickerModal[0]);
            }
            else return false; //nothing found
        }
        pickerModal = $(pickerModal);
        if (pickerModal.length === 0) return false;
        pickerModal.show();
        $.openModal(pickerModal);
        return pickerModal[0];
    };
    $.loginScreen = function (modal) {
        if (!modal) modal = '.login-screen';
        modal = $(modal);
        if (modal.length === 0) return false;
        modal.show();
        if (modal.find('.' + defaults.viewClass).length > 0) {
            $.sizeNavbars(modal.find('.' + defaults.viewClass)[0]);
        }
        $.openModal(modal);
        return modal[0];
    };
    //显示一个消息，会在2秒钟后自动消失
    $.toast = function(msg,opt) {
		var opts = $.extend({
				duration: 2000, //自动消失时间
				extraclass: true, //给toast根节点附加class
				offset:[0,0], //偏移量
				overlay:'', //transparent透明
				callback:function(){}
			}, opt);

        var $toast = $('<div class="modal toast ' + (opts.extraclass || '') + '">' + msg + '</div>' ).appendTo(document.body);
		if (opts.overlay !== false){
			var overlay = $('<div class="modal-overlay '+ (opts.overlay == 'transparent' ? 'modal-overlay-transparent' : 'modal-overlay-visible') +'"></div>').appendTo(document.body);
		}
        $.openModal($toast, function(){
            setTimeout(function() {
				$.closeModal($toast);
				opts.callback($toast);
            }, opts.duration);
        },opts.offset);
    };

    $.openModal = function (modal, cb,offset) {
        modal = $(modal);
        var isModal = modal.hasClass('modal'),
            isNotToast = !modal.hasClass('toast');
        if ($('.modal.modal-in:not(.modal-out)').length && defaults.modalStack && isModal && isNotToast) {
            $.modalStack.push(function () {
                $.openModal(modal, cb);
            });
            return;
        }

		var offsetTop = 0,offsetLeft = 0;
		var isPopover = modal.hasClass('popover');
        var isPopup = modal.hasClass('popup');
        var isLoginScreen = modal.hasClass('login-screen');
        var isPickerModal = modal.hasClass('picker-modal');
        var isToast = modal.hasClass('toast');

		switch(true){
			case $.isArray(offset):
				offsetTop = offset[0];
				offsetLeft = offset[1];
				break;
			case offset == 'bottom':
				offsetTop = 280;
				break;
			case offset == 'top':
				offsetTop = -280;
				break;
		}

        if (isModal) {
            modal.show();
            modal.css({
                marginTop:  - Math.round(modal.outerHeight() / 2) + offsetTop +'px'
            });
        }

        if (isToast) {
            modal.css({
                marginLeft: - Math.round(parseInt(window.getComputedStyle(modal[0]).width) / 2) + offsetLeft + 'px'
            });
        }
        var overlay;
        if (!isLoginScreen && !isPickerModal && !isToast) {
            if ($('.modal-overlay').length === 0 && !isPopup) {
                modal.after('<div class="modal-overlay"></div>');
            }
            if ($('.popup-overlay').length === 0 && isPopup) {
                modal.after('<div class="popup-overlay"></div>');
            }
            overlay = isPopup ? $('.popup-overlay') : $('.modal-overlay');
        }

        var clientLeft = modal[0].clientLeft;

        modal.trigger('open');

        if (isPickerModal) {
            $(defaults.modalContainer).addClass('with-picker-modal');
        }

        if (!isLoginScreen && !isPickerModal && !isToast) overlay.addClass('modal-overlay-visible');
        modal.removeClass('modal-out').addClass('modal-in').transitionEnd(function (e) {
            if (modal.hasClass('modal-out')) modal.trigger('closed');
            else modal.trigger('opened');
        });
        if (typeof cb === 'function') {
          cb.call(this);
        }
        return true;
    };
    $.closeModal = function (modal) {
        modal = $(modal || '.modal-in');
        if (typeof modal !== 'undefined' && modal.length === 0) {
            return;
        }
        var isPopover = modal.hasClass('popover'),
			isModal = modal.hasClass('modal'),
            isPopup = modal.hasClass('popup'),
            isToast = modal.hasClass('toast'),
            isLoginScreen = modal.hasClass('login-screen'),
            isPickerModal = modal.hasClass('picker-modal'),
            removeOnClose = modal.hasClass('remove-on-close'),
            overlay = isPopup ? $('.popup-overlay') : $('.modal-overlay');
        if (isPopup){
            if (modal.length === $('.popup.modal-in').length) {
                overlay.removeClass('modal-overlay-visible');
            }
        }else if (!(isPickerModal)) {
            overlay.removeClass('modal-overlay-visible');
        }

        modal.trigger('close');

        // Picker modal body class
        if (isPickerModal) {
            $(defaults.modalContainer).removeClass('with-picker-modal');
            $(defaults.modalContainer).addClass('picker-modal-closing');
        }

		if (!isPopover) {

            modal.removeClass('modal-in').addClass('modal-out').transitionEnd(function (e) {
                if (modal.hasClass('modal-out')) modal.trigger('closed');
                else modal.trigger('opened');

                if (isPickerModal) {
                    $(defaults.modalContainer).removeClass('picker-modal-closing');
                }
                if (isPopup || isLoginScreen || isPickerModal) {
                    modal.removeClass('modal-out').hide();
                    if (removeOnClose && modal.length > 0) {
                        modal.remove();
                    }
                }
                else {
                    modal.remove();
                }
            });
            if (isModal &&  defaults.modalStack ) {
                $.modalStackClearQueue();
            }
        }else{
			modal.removeClass('modal-in modal-out').trigger('closed').hide();
            if (removeOnClose) {
                modal.remove();
            }
		}
        return true;
    };


    function handleClicks(e) {
        var clicked = $(this);
        var url = clicked.attr('href');


        //Collect Clicked data- attributes
        var clickedData = clicked.dataset();

		// Popover
        if (clicked.hasClass('open-popover')) {
            var popover;
            if (clickedData.popover) {
                popover = clickedData.popover;
            }
            else popover = '.popover';
            $.popover(popover, clicked);
        }
        if (clicked.hasClass('close-popover')) {
            $.closeModal('.popover.modal-in');
        }

        // Popup
        var popup;
        if (clicked.hasClass('open-popup')) {
            if (clickedData.popup) {
                popup = clickedData.popup;
            }else{
				popup = '.popup';
			}
            $.popup(popup);
        }
        if (clicked.hasClass('close-popup')) {
            if (clickedData.popup) {
                popup = clickedData.popup;
            }
            else popup = '.popup.modal-in';
            $.closeModal(popup);
        }

        // Close Modal
        if (clicked.hasClass('modal-overlay')) {
            if ($('.modal.modal-in').length > 0 && defaults.modalCloseByOutside)
                $.closeModal('.modal.modal-in');
            if ($('.actions-modal.modal-in').length > 0 && defaults.actionsCloseByOutside)
                $.closeModal('.actions-modal.modal-in');
			if ($('.popover.modal-in').length > 0) $.closeModal('.popover.modal-in');
        }
        if (clicked.hasClass('popup-overlay')) {
            if ($('.popup.modal-in').length > 0 && defaults.popupCloseByOutside)
                $.closeModal('.popup.modal-in');
        }
    }

    $(document).on('click', ' .modal-overlay, .popup-overlay, .close-popup, .open-popup, .open-popover, .close-popover, .close-picker', handleClicks);
    var defaults =  $.modal.prototype.defaults  = {
        modalStack: true,
        modalButtonOk: '确定',
        modalButtonCancel: '取消',
        modalPreloaderTitle: '加载中',
        modalContainer : document.body
    };
}($);


+ function($) {
    "use strict";
    var Picker = function (params) {
        var p = this;
        var defaults = {
            updateValuesOnMomentum: false,
            updateValuesOnTouchmove: true,
            rotateEffect: false,
            momentumRatio: 7,
            freeMode: false,
            // Common settings
            scrollToInput: true,
            inputReadOnly: true,
            toolbar: true,
            toolbarCloseText: '确定',
            toolbarTemplate: '<header class="bar bar-nav">\
                <button class="button button-link pull-right close-picker">确定</button>\
                <h1 class="title">请选择</h1>\
                </header>',
        };
        params = params || {};
        for (var def in defaults) {
            if (typeof params[def] === 'undefined') {
                params[def] = defaults[def];
            }
        }
        p.params = params;
        p.cols = [];
        p.initialized = false;

        // Inline flag
        p.inline = p.params.container ? true : false;

        // 3D Transforms origin bug, only on safari
        var originBug = $.device.ios || (navigator.userAgent.toLowerCase().indexOf('safari') >= 0 && navigator.userAgent.toLowerCase().indexOf('chrome') < 0) && !$.device.android;

        // Value
        p.setValue = function (arrValues, transition) {
            var valueIndex = 0;
            for (var i = 0; i < p.cols.length; i++) {
                if (p.cols[i] && !p.cols[i].divider) {
                    p.cols[i].setValue(arrValues[valueIndex], transition);
                    valueIndex++;
                }
            }
        };
        p.updateValue = function () {
            var newValue = [];
            var newDisplayValue = [];
            for (var i = 0; i < p.cols.length; i++) {
                if (!p.cols[i].divider) {
                    newValue.push(p.cols[i].value);
                    newDisplayValue.push(p.cols[i].displayValue);
                }
            }
            if (newValue.indexOf(undefined) >= 0) {
                return;
            }
            p.value = newValue;
            p.displayValue = newDisplayValue;
            if (p.params.onChange) {
                p.params.onChange(p, p.value, p.displayValue);
            }
            if (p.input && p.input.length > 0) {
                $(p.input).val(p.params.formatValue ? p.params.formatValue(p, p.value, p.displayValue) : p.value.join(' '));
                $(p.input).trigger('change');
            }
        };

        // Columns Handlers
        p.initPickerCol = function (colElement, updateItems) {
            var colContainer = $(colElement);
            var colIndex = colContainer.index();
            var col = p.cols[colIndex];
            if (col.divider) return;
            col.container = colContainer;
            col.wrapper = col.container.find('.picker-items-col-wrapper');
            col.items = col.wrapper.find('.picker-item');

            var i, j;
            var wrapperHeight, itemHeight, itemsHeight, minTranslate, maxTranslate;
            col.replaceValues = function (values, displayValues) {
                col.destroyEvents();
                col.values = values;
                col.displayValues = displayValues;
                var newItemsHTML = p.columnHTML(col, true);
                col.wrapper.html(newItemsHTML);
                col.items = col.wrapper.find('.picker-item');
                col.calcSize();
                col.setValue(col.values[0], 0, true);
                col.initEvents();
            };
            col.calcSize = function () {
                if (p.params.rotateEffect) {
                    col.container.removeClass('picker-items-col-absolute');
                    if (!col.width) col.container.css({width:''});
                }
                var colWidth, colHeight;
                colWidth = 0;
                colHeight = col.container[0].offsetHeight;
                wrapperHeight = col.wrapper[0].offsetHeight;
                itemHeight = col.items[0].offsetHeight;
                itemsHeight = itemHeight * col.items.length;
                minTranslate = colHeight / 2 - itemsHeight + itemHeight / 2;
                maxTranslate = colHeight / 2 - itemHeight / 2;
                if (col.width) {
                    colWidth = col.width;
                    if (parseInt(colWidth, 10) === colWidth) colWidth = colWidth + 'px';
                    col.container.css({width: colWidth});
                }
                if (p.params.rotateEffect) {
                    if (!col.width) {
                        col.items.each(function () {
                            var item = $(this);
                            item.css({width:'auto'});
                            colWidth = Math.max(colWidth, item[0].offsetWidth);
                            item.css({width:''});
                        });
                        col.container.css({width: (colWidth + 2) + 'px'});
                    }
                    col.container.addClass('picker-items-col-absolute');
                }
            };
            col.calcSize();

            col.wrapper.transform('translate3d(0,' + maxTranslate + 'px,0)').transition(0);


            var activeIndex = 0;
            var animationFrameId;

            // Set Value Function
            col.setValue = function (newValue, transition, valueCallbacks) {
                if (typeof transition === 'undefined') transition = '';
                var newActiveIndex = col.wrapper.find('.picker-item[data-picker-value="' + newValue + '"]').index();
                if(typeof newActiveIndex === 'undefined' || newActiveIndex === -1) {
                    return;
                }
                var newTranslate = -newActiveIndex * itemHeight + maxTranslate;
                // Update wrapper
                col.wrapper.transition(transition);
                col.wrapper.transform('translate3d(0,' + (newTranslate) + 'px,0)');

                // Watch items
                if (p.params.updateValuesOnMomentum && col.activeIndex && col.activeIndex !== newActiveIndex ) {
                    $.cancelAnimationFrame(animationFrameId);
                    col.wrapper.transitionEnd(function(){
                        $.cancelAnimationFrame(animationFrameId);
                    });
                    updateDuringScroll();
                }

                // Update items
                col.updateItems(newActiveIndex, newTranslate, transition, valueCallbacks);
            };

            col.updateItems = function (activeIndex, translate, transition, valueCallbacks) {
                if (typeof translate === 'undefined') {
                    translate = $.getTranslate(col.wrapper[0], 'y');
                }
                if(typeof activeIndex === 'undefined') activeIndex = -Math.round((translate - maxTranslate)/itemHeight);
                if (activeIndex < 0) activeIndex = 0;
                if (activeIndex >= col.items.length) activeIndex = col.items.length - 1;
                var previousActiveIndex = col.activeIndex;
                col.activeIndex = activeIndex;
                col.wrapper.find('.picker-selected').removeClass('picker-selected');
                if (p.params.rotateEffect) {
                    col.items.transition(transition);
                }
                var selectedItem = col.items.eq(activeIndex).addClass('picker-selected').transform('');

                if (valueCallbacks || typeof valueCallbacks === 'undefined') {
                    // Update values
                    col.value = selectedItem.attr('data-picker-value');
                    col.displayValue = col.displayValues ? col.displayValues[activeIndex] : col.value;
                    // On change callback
                    if (previousActiveIndex !== activeIndex) {
                        if (col.onChange) {
                            col.onChange(p, col.value, col.displayValue);
                        }
                        p.updateValue();
                    }
                }

                // Set 3D rotate effect
                if (!p.params.rotateEffect) {
                    return;
                }
                var percentage = (translate - (Math.floor((translate - maxTranslate)/itemHeight) * itemHeight + maxTranslate)) / itemHeight;

                col.items.each(function () {
                    var item = $(this);
                    var itemOffsetTop = item.index() * itemHeight;
                    var translateOffset = maxTranslate - translate;
                    var itemOffset = itemOffsetTop - translateOffset;
                    var percentage = itemOffset / itemHeight;

                    var itemsFit = Math.ceil(col.height / itemHeight / 2) + 1;

                    var angle = (-18*percentage);
                    if (angle > 180) angle = 180;
                    if (angle < -180) angle = -180;
                    // Far class
                    if (Math.abs(percentage) > itemsFit) item.addClass('picker-item-far');
                    else item.removeClass('picker-item-far');
                    // Set transform
                    item.transform('translate3d(0, ' + (-translate + maxTranslate) + 'px, ' + (originBug ? -110 : 0) + 'px) rotateX(' + angle + 'deg)');
                });
            };

            function updateDuringScroll() {
                animationFrameId = $.requestAnimationFrame(function () {
                    col.updateItems(undefined, undefined, 0);
                    updateDuringScroll();
                });
            }

            // Update items on init
            if (updateItems) col.updateItems(0, maxTranslate, 0);

            var allowItemClick = true;
            var isTouched, isMoved, touchStartY, touchCurrentY, touchStartTime, touchEndTime, startTranslate, returnTo, currentTranslate, prevTranslate, velocityTranslate, velocityTime;
            function handleTouchStart (e) {
                if (isMoved || isTouched) return;
                e.preventDefault();
                isTouched = true;
                touchStartY = touchCurrentY = e.type === 'touchstart' ? e.targetTouches[0].pageY : e.pageY;
                touchStartTime = (new Date()).getTime();

                allowItemClick = true;
                startTranslate = currentTranslate = $.getTranslate(col.wrapper[0], 'y');
            }
            function handleTouchMove (e) {
                if (!isTouched) return;
                e.preventDefault();
                allowItemClick = false;
                touchCurrentY = e.type === 'touchmove' ? e.targetTouches[0].pageY : e.pageY;
                if (!isMoved) {
                    // First move
                    $.cancelAnimationFrame(animationFrameId);
                    isMoved = true;
                    startTranslate = currentTranslate = $.getTranslate(col.wrapper[0], 'y');
                    col.wrapper.transition(0);
                }
                e.preventDefault();

                var diff = touchCurrentY - touchStartY;
                currentTranslate = startTranslate + diff;
                returnTo = undefined;

                // Normalize translate
                if (currentTranslate < minTranslate) {
                    currentTranslate = minTranslate - Math.pow(minTranslate - currentTranslate, 0.8);
                    returnTo = 'min';
                }
                if (currentTranslate > maxTranslate) {
                    currentTranslate = maxTranslate + Math.pow(currentTranslate - maxTranslate, 0.8);
                    returnTo = 'max';
                }
                // Transform wrapper
                col.wrapper.transform('translate3d(0,' + currentTranslate + 'px,0)');

                // Update items
                col.updateItems(undefined, currentTranslate, 0, p.params.updateValuesOnTouchmove);

                // Calc velocity
                velocityTranslate = currentTranslate - prevTranslate || currentTranslate;
                velocityTime = (new Date()).getTime();
                prevTranslate = currentTranslate;
            }
            function handleTouchEnd (e) {
                if (!isTouched || !isMoved) {
                    isTouched = isMoved = false;
                    return;
                }
                isTouched = isMoved = false;
                col.wrapper.transition('');
                if (returnTo) {
                    if (returnTo === 'min') {
                        col.wrapper.transform('translate3d(0,' + minTranslate + 'px,0)');
                    }
                    else col.wrapper.transform('translate3d(0,' + maxTranslate + 'px,0)');
                }
                touchEndTime = new Date().getTime();
                var velocity, newTranslate;
                if (touchEndTime - touchStartTime > 300) {
                    newTranslate = currentTranslate;
                }
                else {
                    velocity = Math.abs(velocityTranslate / (touchEndTime - velocityTime));
                    newTranslate = currentTranslate + velocityTranslate * p.params.momentumRatio;
                }

                newTranslate = Math.max(Math.min(newTranslate, maxTranslate), minTranslate);

                // Active Index
                var activeIndex = -Math.floor((newTranslate - maxTranslate)/itemHeight);

                // Normalize translate
                if (!p.params.freeMode) newTranslate = -activeIndex * itemHeight + maxTranslate;

                // Transform wrapper
                col.wrapper.transform('translate3d(0,' + (parseInt(newTranslate,10)) + 'px,0)');

                // Update items
                col.updateItems(activeIndex, newTranslate, '', true);

                // Watch items
                if (p.params.updateValuesOnMomentum) {
                    updateDuringScroll();
                    col.wrapper.transitionEnd(function(){
                        $.cancelAnimationFrame(animationFrameId);
                    });
                }

                // Allow click
                setTimeout(function () {
                    allowItemClick = true;
                }, 100);
            }

            function handleClick(e) {
                if (!allowItemClick) return;
                $.cancelAnimationFrame(animationFrameId);
                /*jshint validthis:true */
                var value = $(this).attr('data-picker-value');
                col.setValue(value);
            }

            col.initEvents = function (detach) {
                var method = detach ? 'off' : 'on';
                col.container[method]($.touchEvents.start, handleTouchStart);
                col.container[method]($.touchEvents.move, handleTouchMove);
                col.container[method]($.touchEvents.end, handleTouchEnd);
                col.items[method]('click', handleClick);
            };
            col.destroyEvents = function () {
                col.initEvents(true);
            };

            col.container[0].destroyPickerCol = function () {
                col.destroyEvents();
            };

            col.initEvents();

        };
        p.destroyPickerCol = function (colContainer) {
            colContainer = $(colContainer);
            if ('destroyPickerCol' in colContainer[0]) colContainer[0].destroyPickerCol();
        };
        // Resize cols
        function resizeCols() {
            if (!p.opened) return;
            for (var i = 0; i < p.cols.length; i++) {
                if (!p.cols[i].divider) {
                    p.cols[i].calcSize();
                    p.cols[i].setValue(p.cols[i].value, 0, false);
                }
            }
        }
        $(window).on('resize', resizeCols);

        // HTML Layout
        p.columnHTML = function (col, onlyItems) {
            var columnItemsHTML = '';
            var columnHTML = '';
            if (col.divider) {
                columnHTML += '<div class="picker-items-col picker-items-col-divider ' + (col.textAlign ? 'picker-items-col-' + col.textAlign : '') + ' ' + (col.cssClass || '') + '">' + col.content + '</div>';
            }
            else {
                for (var j = 0; j < col.values.length; j++) {
                    columnItemsHTML += '<div class="picker-item" data-picker-value="' + col.values[j] + '">' + (col.displayValues ? col.displayValues[j] : col.values[j]) + '</div>';
                }

                columnHTML += '<div class="picker-items-col ' + (col.textAlign ? 'picker-items-col-' + col.textAlign : '') + ' ' + (col.cssClass || '') + '"><div class="picker-items-col-wrapper">' + columnItemsHTML + '</div></div>';
            }
            return onlyItems ? columnItemsHTML : columnHTML;
        };
        p.layout = function () {
            var pickerHTML = '';
            var pickerClass = '';
            var i;
            p.cols = [];
            var colsHTML = '';
            for (i = 0; i < p.params.cols.length; i++) {
                var col = p.params.cols[i];
                colsHTML += p.columnHTML(p.params.cols[i]);
                p.cols.push(col);
            }
            pickerClass = 'picker-modal picker-columns ' + (p.params.cssClass || '') + (p.params.rotateEffect ? ' picker-3d' : '');
            pickerHTML =
                '<div class="' + (pickerClass) + '">' +
                (p.params.toolbar ? p.params.toolbarTemplate.replace(/{{closeText}}/g, p.params.toolbarCloseText) : '') +
                '<div class="picker-modal-inner picker-items">' +
                colsHTML +
                '<div class="picker-center-highlight"></div>' +
                '</div>' +
                '</div>';

            p.pickerHTML = pickerHTML;
        };

        // Input Events
        function openOnInput(e) {
            e.preventDefault();
            // 安卓微信webviewreadonly的input依然弹出软键盘问题修复
            if ($.device.isWeixin && $.device.android && p.params.inputReadOnly) {
                /*jshint validthis:true */
                this.focus();
                this.blur();
            }
            if (p.opened) return;
            p.open();
            if (p.params.scrollToInput) {
                var pageContent = p.input.parents('.page-content');
                if (pageContent.length === 0) return;

                var paddingTop = parseInt(pageContent.css('padding-top'), 10),
                    paddingBottom = parseInt(pageContent.css('padding-bottom'), 10),
                    pageHeight = pageContent[0].offsetHeight - paddingTop - p.container.height(),
                    pageScrollHeight = pageContent[0].scrollHeight - paddingTop - p.container.height(),
                    newPaddingBottom;
                var inputTop = p.input.offset().top - paddingTop + p.input[0].offsetHeight;
                if (inputTop > pageHeight) {
                    var scrollTop = pageContent.scrollTop() + inputTop - pageHeight;
                    if (scrollTop + pageHeight > pageScrollHeight) {
                        newPaddingBottom = scrollTop + pageHeight - pageScrollHeight + paddingBottom;
                        if (pageHeight === pageScrollHeight) {
                            newPaddingBottom = p.container.height();
                        }
                        pageContent.css({'padding-bottom': (newPaddingBottom) + 'px'});
                    }
                    pageContent.scrollTop(scrollTop, 300);
                }
            }
        }
        function closeOnHTMLClick(e) {
            if (!p.opened) return;
            if (p.input && p.input.length > 0) {
                if (e.target !== p.input[0] && $(e.target).parents('.picker-modal').length === 0) p.close();
            }
            else {
                if ($(e.target).parents('.picker-modal').length === 0) p.close();
            }
        }

        if (p.params.input) {
            p.input = $(p.params.input);
            if (p.input.length > 0) {
                if (p.params.inputReadOnly) p.input.prop('readOnly', true);
                if (!p.inline) {
                    p.input.on('click', openOnInput);
                }
            }
        }

        if (!p.inline) $('html').on('click', closeOnHTMLClick);

        // Open
        function onPickerClose() {
            p.opened = false;
            if (p.input && p.input.length > 0) p.input.parents('.page-content').css({'padding-bottom': ''});
            if (p.params.onClose) p.params.onClose(p);

            // Destroy events
            p.container.find('.picker-items-col').each(function () {
                p.destroyPickerCol(this);
            });
        }

        p.opened = false;
        p.open = function () {
            if (!p.opened) {

                // Layout
                p.layout();

                // Append
                if (p.inline) {
                    p.container = $(p.pickerHTML);
                    p.container.addClass('picker-modal-inline');
                    $(p.params.container).append(p.container);
                    p.opened = true;
                }
                else {
                    p.container = $($.pickerModal(p.pickerHTML));
                    $(p.container)
                        .one('opened', function() {
                            p.opened = true;
                        })
                        .on('close', function () {
                            onPickerClose();
                        });
                }

                // Store picker instance
                p.container[0].f7Picker = p;

                // Init Events
                p.container.find('.picker-items-col').each(function () {
                    var updateItems = true;
                    if ((!p.initialized && p.params.value) || (p.initialized && p.value)) updateItems = false;
                    p.initPickerCol(this, updateItems);
                });

                // Set value
                if (!p.initialized) {
                    if (p.params.value) {
                        p.setValue(p.params.value, 0);
                    }
                }
                else {
                    if (p.value) p.setValue(p.value, 0);
                }
            }

            // Set flag
            p.initialized = true;

            if (p.params.onOpen) p.params.onOpen(p);
        };

        // Close
        p.close = function () {
            if (!p.opened || p.inline) return;
            $.closeModal(p.container);
            return;
        };

        // Destroy
        p.destroy = function () {
            p.close();
            if (p.params.input && p.input.length > 0) {
                p.input.off('click', openOnInput);
            }
            $('html').off('click', closeOnHTMLClick);
            $(window).off('resize', resizeCols);
        };

        if (p.inline) {
            p.open();
        }

        return p;
    };

    $(document).on("click", ".close-picker", function() {
        var pickerToClose = $('.picker-modal.modal-in');
        $.closeModal(pickerToClose);
    });

    $.fn.picker = function(params) {
        var args = arguments;
        return this.each(function() {
            if(!this) return;
            var $this = $(this);

            var picker = $this.data("picker");
            if(!picker) {
                var p = $.extend({
                    input: this,
                    value: $this.val() ? $this.val().split(' ') : ''
                }, params);
                picker = new Picker(p);
                $this.data("picker", picker);
            }
            if(typeof params === typeof "a") {
                picker[params].apply(picker, Array.prototype.slice.call(args, 1));
            }
        });
    };
}($);

+ function($) {
    "use strict";

    var today = new Date();

    var getDays = function(max) {
        var days = [];
        for(var i=1; i<= (max||31);i++) {
            days.push(i < 10 ? "0"+i : i);
        }
        return days;
    };

    var getDaysByMonthAndYear = function(month, year) {
        var int_d = new Date(year, parseInt(month)+1-1, 1);
        var d = new Date(int_d - 1);
        return getDays(d.getDate());
    };

    var formatNumber = function (n) {
        return n < 10 ? "0" + n : n;
    };

    var initMonthes = ('01 02 03 04 05 06 07 08 09 10 11 12').split(' ');

    var initYears = (function () {
        var arr = [];
        for (var i = 1950; i <= 2030; i++) { arr.push(i); }
        return arr;
    })();


    var defaults = {

        rotateEffect: false,  //为了性能

        value: [today.getFullYear(), formatNumber(today.getMonth()+1), formatNumber(today.getDate()), today.getHours(), formatNumber(today.getMinutes())],

        onChange: function (picker, values, displayValues) {
            var days = getDaysByMonthAndYear(picker.cols[1].value, picker.cols[0].value);
            var currentValue = picker.cols[2].value;
            if(currentValue > days.length) currentValue = days.length;
            picker.cols[2].setValue(currentValue);
        },

        formatValue: function (p, values, displayValues) {
            return displayValues[0] + '-' + values[1] + '-' + values[2] + ' ' + values[3] + ':' + values[4];
        },

        cols: [
            // Years
        {
            values: initYears
        },
        // Months
        {
            values: initMonthes
        },
        // Days
        {
            values: getDays()
        },

        // Space divider
        {
            divider: true,
            content: '  '
        },
        // Hours
        {
            values: (function () {
                var arr = [];
                for (var i = 0; i <= 23; i++) { arr.push(i); }
                return arr;
            })(),
        },
        // Divider
        {
            divider: true,
            content: ':'
        },
        // Minutes
        {
            values: (function () {
                var arr = [];
                for (var i = 0; i <= 59; i++) { arr.push(i < 10 ? '0' + i : i); }
                return arr;
            })(),
        }
        ]
    };

    $.fn.datetimePicker = function(params) {
        return this.each(function() {
            if(!this) return;
            var p = $.extend(defaults, params);
            $(this).picker(p);
            if (params.value) $(this).val(p.formatValue(p, p.value, p.value));
        });
    };

}($);


+function ($) {
    "use strict";

    $.accordionToggle = function (item) {
        item = $(item);
        if (item.length === 0) return;
        if (item.hasClass('accordion-item-expanded')) $.accordionClose(item);
        else $.accordionOpen(item);
    };
    $.accordionOpen = function (item) {
        item = $(item);
        var list = item.parents('.accordion-list').eq(0);
        var content = item.children('.accordion-item-content');
        if (content.length === 0) content = item.find('.accordion-item-content');
        var expandedItem = list.length > 0 && item.parent().children('.accordion-item-expanded');
        if (expandedItem.length > 0) {
            $.accordionClose(expandedItem);
        }
        content.show().css('height', content[0].scrollHeight + 'px').transitionEnd(function () {
            if (item.hasClass('accordion-item-expanded')) {
                item.trigger('opened');
            }
            else {
                content.css('height', '');
                item.trigger('closed');
            }
        });
        item.trigger('open');
        item.addClass('accordion-item-expanded');
    };
    $.accordionClose = function (item) {
        item = $(item);
        var content = item.children('.accordion-item-content');
        if (content.length === 0) content = item.find('.accordion-item-content');
        item.removeClass('accordion-item-expanded');
        content.css('height', '').transitionEnd(function () {
            if (item.hasClass('accordion-item-expanded')) {
                item.trigger('opened');
            }else{
                content.css({display:'',height:''});
                item.trigger('closed');
            }
        })
        item.trigger('close');
    };

    $(document).on("click", ".accordion-item .item-content, .accordion-item-toggle", function(e) {
        e.preventDefault();
        var clicked = $(this);
        if (clicked.hasClass('accordion-item-toggle') || clicked.parent().hasClass('accordion-item')) {
            var accordionItem = clicked.parent('.accordion-item');
            if (accordionItem.length === 0) accordionItem = clicked.parents('.accordion-item');
            if (accordionItem.length === 0) accordionItem = clicked.parents('li');
            $.accordionToggle(accordionItem);
        }
    });
}($);


+function ($) {
    "use strict";

    var showTab = function (tab, tabLink, force) {
        var newTab = $(tab);
        if (arguments.length === 2) {
            if (typeof tabLink === 'boolean') {
                force = tabLink;
            }
        }
        if (newTab.length === 0) return false;
        if (newTab.hasClass('active')) {
            if (force) newTab.trigger('show');
            return false;
        }
        var tabs = newTab.parent('.tabs');
        if (tabs.length === 0) return false;

		// Animated tabs
		var isAnimatedTabs = tabs.parent().hasClass('tabs-animated-wrap');
		if (isAnimatedTabs) {
			tabs.transform('translate3d(' + -newTab.index() * 100 + '%,0,0)');
		}

        var oldTab = tabs.children('.tab.active').removeClass('active');
        newTab.addClass('active');
        newTab.trigger('show');

		// Update navbars in new tab
		if (!isAnimatedTabs && newTab.find('.navbar').length > 0) {
			// Find tab's view
			var viewContainer;
			if (newTab.hasClass(app.params.viewClass)) viewContainer = newTab[0];
			else viewContainer = newTab.parents('.' + app.params.viewClass)[0];
			app.sizeNavbars(viewContainer);
		}

        // Find related link for new tab
        if (tabLink) tabLink = $(tabLink);
        else {
            // Search by id
            if (typeof tab === 'string') tabLink = $('.tab-link[href="' + tab + '"]');
            else tabLink = $('.tab-link[href="#' + newTab.attr('id') + '"]');
            // Search by data-tab
            if (!tabLink || tabLink && tabLink.length === 0) {
                $('[data-tab]').each(function () {
                    if (newTab.is($(this).attr('data-tab'))) tabLink = $(this);
                });
            }
        }
        if (tabLink.length === 0) return;

        // Find related link for old tab
        var oldTabLink;
        if (oldTab && oldTab.length > 0) {
            // Search by id
            var oldTabId = oldTab.attr('id');
            if (oldTabId) oldTabLink = $('.tab-link[href="#' + oldTabId + '"]');
            // Search by data-tab
            if (!oldTabLink || oldTabLink && oldTabLink.length === 0) {
                $('[data-tab]').each(function () {
                    if (oldTab.is($(this).attr('data-tab'))) oldTabLink = $(this);
                });
            }
        }

        // Update links' classes
        if (tabLink && tabLink.length > 0) tabLink.addClass('active');
        if (oldTabLink && oldTabLink.length > 0) oldTabLink.removeClass('active');
        tabLink.trigger('active');

        return true;
    };

    var old = $.showTab;
    $.showTab = showTab;

    $.showTab.noConflict = function () {
        $.showTab = old;
        return this;
    };
    //a标签上的click事件，在iscroll下响应有问题
    $(document).on("click", ".tab-link", function(e) {
        e.preventDefault();
        var $target = $(this);
			showTab($target.data("tab") || $target.attr("href"), $target);
    });



}($);


+function ($) {
    "use strict";
    $.initFixedTab = function(){
        var $fixedTab = $('.fixed-tab');
        if ($fixedTab.length === 0) return;
        $('.fixed-tab').fixedTab();//默认{offset: 0}
    };
    var FixedTab = function(pageContent, _options) {
        var $pageContent = this.$pageContent = $(pageContent);
        var shadow = $pageContent.clone();
        var fixedTop = $pageContent[0].getBoundingClientRect().top;

        shadow.css('visibility', 'hidden');
        this.options = $.extend({}, this._defaults, {
            fixedTop: fixedTop,
            shadow: shadow,
            offset: 0
        }, _options);

        this._bindEvents();
    };

    FixedTab.prototype = {
        _defaults: {
            offset: 0,
        },
        _bindEvents: function() {
            this.$pageContent.parents('.page-content').on('scroll', this._scrollHandler.bind(this));
            this.$pageContent.on('active', '.tab-link', this._tabLinkHandler.bind(this));
        },
        _tabLinkHandler: function(ev) {
            var isFixed = $(ev.target).parents('.buttons-fixed').length > 0;
            var fixedTop = this.options.fixedTop;
            var offset = this.options.offset;
            $.refreshScroller();
            if (!isFixed) return;
            this.$pageContent.parents('.page-content').scrollTop(fixedTop - offset);
        },
        // 滚动核心代码
        _scrollHandler: function(ev) {
            var $scroller = $(ev.target);
            var $pageContent = this.$pageContent;
            var shadow = this.options.shadow;
            var offset = this.options.offset;
            var fixedTop = this.options.fixedTop;
            var scrollTop = $scroller.scrollTop();
            var isFixed = scrollTop >= fixedTop - offset;
            if (isFixed) {
                shadow.insertAfter($pageContent);
                $pageContent.addClass('buttons-fixed').css('top', offset);
            } else {
                shadow.remove();
                $pageContent.removeClass('buttons-fixed').css('top', 0);
            }
        }
    };

    function Plugin(option) {
        var args = Array.apply(null, arguments);
        args.shift();
        this.each(function() {
            var $this = $(this);
            var options = $.extend({}, $this.dataset(), typeof option === 'object' && option);
            var data = $this.data('fixedtab');
            if (!data) {
                //获取data-api的
                $this.data('fixedtab', (data = new FixedTab(this, options)));
            }
        });

    }
    $.fn.fixedTab = Plugin;
    $.fn.fixedTab.Constructor = FixedTab;
    $.initFixedTab();



}($);


+ function($) {
    'use strict';
    $.initPullToRefresh = function(pageContainer) {

        var eventsTarget = $(pageContainer);
        if (!eventsTarget.hasClass('pull-to-refresh-content')) {
            eventsTarget = eventsTarget.find('.pull-to-refresh-content');
        }
        if (!eventsTarget || eventsTarget.length === 0) return;

        var isTouched, isMoved, touchesStart = {},
            isScrolling, touchesDiff, touchStartTime, container, refresh = false,
            useTranslate = false,
            startTranslate = 0,
            translate, scrollTop, wasScrolled, triggerDistance, dynamicTriggerDistance;

        container = eventsTarget;


        if (container.attr('data-ptr-distance')) {
            dynamicTriggerDistance = true;
        } else {
            triggerDistance = 44;
        }

        function handleTouchStart(e) {

            if (isTouched) {
                if ($.device.android) {
                    if ('targetTouches' in e && e.targetTouches.length > 1) return;
                } else return;
            }

			var position = $.getTouchPosition(e);
				isMoved = false;
				isTouched = true;
				isScrolling = undefined;
				wasScrolled = undefined;
				touchesStart.x = position.x;
				touchesStart.y = position.y;
				touchStartTime = (new Date()).getTime();
				container = $(this);
        }

        function handleTouchMove(e) {
            if (!isTouched) return;
			var position = $.getTouchPosition(e);
            var pageX = position.x;
            var pageY = position.y;
            if (typeof isScrolling === 'undefined') {
                isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
            }
            if (!isScrolling) {
                isTouched = false;
                return;
            }

            scrollTop = container[0].scrollTop;
            if (typeof wasScrolled === 'undefined' && scrollTop !== 0) wasScrolled = true;

            if (!isMoved) {
                container.removeClass('transitioning');
                if (scrollTop > container[0].offsetHeight) {
                    isTouched = false;
                    return;
                }
                if (dynamicTriggerDistance) {
                    triggerDistance = container.attr('data-ptr-distance');
                    if (triggerDistance.indexOf('%') >= 0) triggerDistance = container[0].offsetHeight * parseInt(triggerDistance, 10) / 100;
                }
                startTranslate = container.hasClass('refreshing') ? triggerDistance : 0;
                if (container[0].scrollHeight === container[0].offsetHeight || !$.device.ios) {
                    useTranslate = true;
                } else {
                    useTranslate = false;
                }
                useTranslate = true;
            }
            isMoved = true;
            touchesDiff = pageY - touchesStart.y;

            if (touchesDiff > 0 && scrollTop <= 0 || scrollTop < 0) {
                // iOS 8 fix
                if ($.device.ios && parseInt($.device.osVersion.split('.')[0], 10) > 7 && scrollTop === 0 && !wasScrolled) useTranslate = true;

                if (useTranslate) {
                    e.preventDefault();
                    translate = (Math.pow(touchesDiff, 0.85) + startTranslate);
                    container.transform('translate3d(0,' + translate + 'px,0)');
                } else {}
                if ((useTranslate && Math.pow(touchesDiff, 0.85) > triggerDistance) || (!useTranslate && touchesDiff >= triggerDistance * 2)) {
                    refresh = true;
                    container.addClass('pull-up').removeClass('pull-down');
                } else {
                    refresh = false;
                    container.removeClass('pull-up').addClass('pull-down');
                }
            } else {

                container.removeClass('pull-up pull-down');
                refresh = false;
                return;
            }
        }

        function handleTouchEnd() {
            if (!isTouched || !isMoved) {
                isTouched = false;
                isMoved = false;
                return;
            }
            if (translate) {
                container.addClass('transitioning');
                translate = 0;
            }
            container.transform('');
            if (refresh) {
                //防止二次触发
                if(container.hasClass('refreshing')) return;
                container.addClass('refreshing');
                container.trigger('refresh');
            } else {
                container.removeClass('pull-down');
            }
            isTouched = false;
            isMoved = false;
        }
        // Attach Events
        eventsTarget.on($.touchEvents.start, handleTouchStart);
        eventsTarget.on($.touchEvents.move, handleTouchMove);
        eventsTarget.on($.touchEvents.end, handleTouchEnd);


        function destroyPullToRefresh() {
            eventsTarget.off($.touchEvents.start, handleTouchStart);
            eventsTarget.off($.touchEvents.move, handleTouchMove);
            eventsTarget.off($.touchEvents.end, handleTouchEnd);
        }
        eventsTarget[0].destroyPullToRefresh = destroyPullToRefresh;

    };
    $.pullToRefreshDone = function(container) {
        $(window).scrollTop(0);//解决微信下拉刷新顶部消失的问题
        container = $(container);
        if (container.length === 0) container = $('.pull-to-refresh-content.refreshing');
        container.removeClass('refreshing').addClass('transitioning');
        container.transitionEnd(function() {
            container.removeClass('transitioning pull-up pull-down');
        });
    };
    $.pullToRefreshTrigger = function(container) {
        container = $(container);
        if (container.length === 0) container = $('.pull-to-refresh-content');
        if (container.hasClass('refreshing')) return;
        container.addClass('transitioning refreshing');
        container.trigger('refresh');
    };

    $.destroyPullToRefresh = function(pageContainer) {
        pageContainer = $(pageContainer);
        var pullToRefreshContent = pageContainer.hasClass('pull-to-refresh-content') ? pageContainer : pageContainer.find('.pull-to-refresh-content');
        if (pullToRefreshContent.length === 0) return;
        if (pullToRefreshContent[0].destroyPullToRefresh) pullToRefreshContent[0].destroyPullToRefresh();
    };

}($);

+ function($) {
    'use strict';

    function handleInfiniteScroll() {
        var inf = $(this);
        var scroller = $.getScroller(inf);
        var scrollTop = scroller.scrollTop();
        var scrollHeight = scroller.scrollHeight();
        var height = inf[0].offsetHeight;
        var distance = inf[0].getAttribute('data-distance');
        var virtualListContainer = inf.find('.virtual-list');
        var virtualList;
        var onTop = inf.hasClass('infinite-scroll-top');
        if (!distance) distance = 50;
        if (typeof distance === 'string' && distance.indexOf('%') >= 0) {
            distance = parseInt(distance, 10) / 100 * height;
        }
        if (distance > height) distance = height;
        if (onTop) {
            if (scrollTop < distance) {
                inf.trigger('infinite');
            }
        } else {
            if (scrollTop + height >= scrollHeight - distance) {
                if (virtualListContainer.length > 0) {
                    virtualList = virtualListContainer[0].f7VirtualList;
                    if (virtualList && !virtualList.reachEnd) return;
                }
                inf.trigger('infinite');
            }
        }

    }
    $.attachInfiniteScroll = function(infiniteContent) {
        $.getScroller(infiniteContent).on('scroll', handleInfiniteScroll);
    };
    $.detachInfiniteScroll = function(infiniteContent) {
        $.getScroller(infiniteContent).off('scroll', handleInfiniteScroll);
    };

    $.initInfiniteScroll = function(pageContainer) {
        pageContainer = $(pageContainer);
        var infiniteContent = pageContainer.hasClass('infinite-scroll')?pageContainer:pageContainer.find('.infinite-scroll');
        if (infiniteContent.length === 0) return;
        $.attachInfiniteScroll(infiniteContent);
        //如果是顶部无限刷新，要将滚动条初始化于最下端
        pageContainer.forEach(function(v){
            if($(v).hasClass('infinite-scroll-top')){
                var height = v.scrollHeight - v.clientHeight;
                $(v).scrollTop(height);
            }
        });
        function detachEvents() {
            $.detachInfiniteScroll(infiniteContent);
            pageContainer.off('pageBeforeRemove', detachEvents);
        }
        pageContainer.on('pageBeforeRemove', detachEvents);
    };
}($);

+function ($) {
    "use strict";
    $(function() {
        $(document).on("focus", ".searchbar input", function(e) {
            var $input = $(e.target);
            $input.parents(".searchbar").addClass("searchbar-active");
        });
        $(document).on("click", ".searchbar-cancel", function(e) {
            var $btn = $(e.target);
            $btn.parents(".searchbar").removeClass("searchbar-active");
        });
        $(document).on("blur", ".searchbar input", function(e) {
            var $input = $(e.target);
            $input.parents(".searchbar").removeClass("searchbar-active");
        });
    });
}($);


+function ($) {
    "use strict";
    $.allowPanelOpen = true;
    $.openPanel = function (panel) {
        if (!$.allowPanelOpen) return false;
        if(panel === 'left' || panel === 'right') panel = ".panel-" + panel;  //可以传入一个方向
        panel = panel ? $(panel) : $(".panel").eq(0);
        var direction = panel.hasClass("panel-right") ? "right" : "left";
        if (panel.length === 0 || panel.hasClass('active')) return false;
        $.closePanel(); // Close if some panel is opened
        $.allowPanelOpen = false;
        var effect = panel.hasClass('panel-reveal') ? 'reveal' : 'cover';
        panel.css({display: 'block'}).addClass('active');
        panel.trigger('open');
        var clientLeft = panel[0].clientLeft;
        var transitionEndTarget = effect === 'reveal' ? $.getCurrentPage() : panel;
        var openedTriggered = false;

        function panelTransitionEnd() {
            transitionEndTarget.transitionEnd(function (e) {
                if (e.target === transitionEndTarget[0]) {
                    if (panel.hasClass('active')) {
                        panel.trigger('opened');
                    }
                    else {
                        panel.trigger('closed');
                    }
            $.allowPanelOpen = true;
                }
                else panelTransitionEnd();
            });
        }
        panelTransitionEnd();

        $(document.body).addClass('with-panel-' + direction + '-' + effect);
        return true;
    };
    $.closePanel = function () {
        var activePanel = $('.panel.active');
        if (activePanel.length === 0) return false;
        var effect = activePanel.hasClass('panel-reveal') ? 'reveal' : 'cover';
        var panelPosition = activePanel.hasClass('panel-left') ? 'left' : 'right';
        activePanel.removeClass('active');
        var transitionEndTarget = effect === 'reveal' ? $('.page') : activePanel;
        activePanel.trigger('close');
        $.allowPanelOpen = false;

        transitionEndTarget.transitionEnd(function () {
            if (activePanel.hasClass('active')) return;
            activePanel.css({display: ''});
            activePanel.trigger('closed');
            $('body').removeClass('panel-closing');
            $.allowPanelOpen = true;
        });

        $('body').addClass('panel-closing').removeClass('with-panel-' + panelPosition + '-' + effect);
    };

    $(document).on("click", ".open-panel", function(e) {
        var panel = $(this).attr('data-panel');
        $.openPanel(panel);
    });
    $(document).on("click", ".close-panel, .panel-overlay", function(e) {
        $.closePanel();
    });

    $.initSwipePanels = function () {
        var panel, side;
        var swipePanel = $.smConfig.swipePanel;
        var swipePanelOnlyClose = $.smConfig.swipePanelOnlyClose;
        var swipePanelCloseOpposite = true;
        var swipePanelActiveArea = false;
        var swipePanelThreshold = 2;
        var swipePanelNoFollow = false;

        if(!(swipePanel || swipePanelOnlyClose)) return;

        var panelOverlay = $('.panel-overlay');
        var isTouched, isMoved, isScrolling, touchesStart = {}, touchStartTime, touchesDiff, translate, opened, panelWidth, effect, direction;
        var views = $('.page');

        function handleTouchStart(e) {

            if (!$.allowPanelOpen || (!swipePanel && !swipePanelOnlyClose) || isTouched) return;
            if ($('.modal-in, .photo-browser-in').length > 0) return;
            if (!(swipePanelCloseOpposite || swipePanelOnlyClose)) {
                if ($('.panel.active').length > 0 && !panel.hasClass('active')) return;
            }
            var position = $.getTouchPosition(e);
			touchesStart.x = position.x;
			touchesStart.y = position.y;
            if (swipePanelCloseOpposite || swipePanelOnlyClose) {
                if ($('.panel.active').length > 0) {
                    side = $('.panel.active').hasClass('panel-left') ? 'left' : 'right';
                }
                else {
                    if (swipePanelOnlyClose) return;
                    side = swipePanel;
                }
                if (!side) return;
            }
            panel = $('.panel.panel-' + side);
            if(!panel[0]) return;
            opened = panel.hasClass('active');
            if (swipePanelActiveArea && !opened) {
                if (side === 'left') {
                    if (touchesStart.x > swipePanelActiveArea) return;
                }
                if (side === 'right') {
                    if (touchesStart.x < window.innerWidth - swipePanelActiveArea) return;
                }
            }
            isMoved = false;
            isTouched = true;
            isScrolling = undefined;

            touchStartTime = (new Date()).getTime();
            direction = undefined;
        }
        function handleTouchMove(e) {
            if (!isTouched) return;
            if(!panel[0]) return;
			var position = $.getTouchPosition(e);
			var pageX = position.x;
			var pageY = position.y;
            if (typeof isScrolling === 'undefined') {
                isScrolling = !!(isScrolling || Math.abs(pageY - touchesStart.y) > Math.abs(pageX - touchesStart.x));
            }
            if (isScrolling) {
                isTouched = false;
                return;
            }
            if (!direction) {
                if (pageX > touchesStart.x) {
                    direction = 'to-right';
                }
                else {
                    direction = 'to-left';
                }

                if (
                        side === 'left' &&
                        (
                         direction === 'to-left' && !panel.hasClass('active')
                        ) ||
                        side === 'right' &&
                        (
                         direction === 'to-right' && !panel.hasClass('active')
                        )
                   )
                {
                    isTouched = false;
                    return;
                }
            }

            if (swipePanelNoFollow) {
                var timeDiff = (new Date()).getTime() - touchStartTime;
                if (timeDiff < 300) {
                    if (direction === 'to-left') {
                        if (side === 'right') $.openPanel(side);
                        if (side === 'left' && panel.hasClass('active')) $.closePanel();
                    }
                    if (direction === 'to-right') {
                        if (side === 'left') $.openPanel(side);
                        if (side === 'right' && panel.hasClass('active')) $.closePanel();
                    }
                }
                isTouched = false;
                isMoved = false;
                return;
            }

            if (!isMoved) {
                effect = panel.hasClass('panel-cover') ? 'cover' : 'reveal';
                if (!opened) {
                    panel.show();
                    panelOverlay.show();
                }
                panelWidth = panel[0].offsetWidth;
                panel.transition(0);
            }

            isMoved = true;

            e.preventDefault();
            var threshold = opened ? 0 : -swipePanelThreshold;
            if (side === 'right') threshold = -threshold;

            touchesDiff = pageX - touchesStart.x + threshold;

            if (side === 'right') {
                translate = touchesDiff  - (opened ? panelWidth : 0);
                if (translate > 0) translate = 0;
                if (translate < -panelWidth) {
                    translate = -panelWidth;
                }
            }
            else {
                translate = touchesDiff  + (opened ? panelWidth : 0);
                if (translate < 0) translate = 0;
                if (translate > panelWidth) {
                    translate = panelWidth;
                }
            }
            if (effect === 'reveal') {
                views.transform('translate3d(' + translate + 'px,0,0)').transition(0);
                panelOverlay.transform('translate3d(' + translate + 'px,0,0)');
            }
            else {
                panel.transform('translate3d(' + translate + 'px,0,0)').transition(0);
            }
        }
        function handleTouchEnd(e) {
            if (!isTouched || !isMoved) {
                isTouched = false;
                isMoved = false;
                return;
            }
            isTouched = false;
            isMoved = false;
            var timeDiff = (new Date()).getTime() - touchStartTime;
            var action;
            var edge = (translate === 0 || Math.abs(translate) === panelWidth);

            if (!opened) {
                if (translate === 0) {
                    action = 'reset';
                }
                else if (
                        timeDiff < 300 && Math.abs(translate) > 0 ||
                        timeDiff >= 300 && (Math.abs(translate) >= panelWidth / 2)
                        ) {
                            action = 'swap';
                        }
                else {
                    action = 'reset';
                }
            }
            else {
                if (translate === -panelWidth) {
                    action = 'reset';
                }
                else if (
                        timeDiff < 300 && Math.abs(translate) >= 0 ||
                        timeDiff >= 300 && (Math.abs(translate) <= panelWidth / 2)
                        ) {
                            if (side === 'left' && translate === panelWidth){
								action = 'reset';
							}else{
								action = 'swap';
							}
                        }
                else {
                    action = 'reset';
                }
            }
            if (action === 'swap') {
                $.allowPanelOpen = true;
                if (opened) {
                    $.closePanel();
                    if (edge) {
                        panel.css({display: ''});
                        $('body').removeClass('panel-closing');
                    }
                }
                else {
                    $.openPanel(side);
                }
                if (edge) $.allowPanelOpen = true;
            }
            if (action === 'reset') {
                if (opened) {
                    $.allowPanelOpen = true;
                    $.openPanel(side);
                }
                else {
                    $.closePanel();
                    if (edge) {
                        $.allowPanelOpen = true;
                        panel.css({display: ''});
                    }
                    else {
                        var target = effect === 'reveal' ? views : panel;
                        $('body').addClass('panel-closing');
                        target.transitionEnd(function () {
                            $.allowPanelOpen = true;
                            panel.css({display: ''});
                            $('body').removeClass('panel-closing');
                        });
                    }
                }
            }
            if (effect === 'reveal') {
                views.transition('');
                views.transform('');
            }
            panel.transition('').transform('');
            panelOverlay.css({display: ''}).transform('');
        }
        $(document).on($.touchEvents.start, handleTouchStart)
		.on($.touchEvents.move, handleTouchMove)
		.on($.touchEvents.end, handleTouchEnd);
    };

    $.initSwipePanels();
}($);


+function ($) {
  "use strict";

  var noti, defaults, timeout, start, diffX, diffY;

  var touchStart = function(e) {
    var p = $.getTouchPosition(e);
    start = p;
    diffX = diffY = 0;
    noti.addClass("touching");
  };
  var touchMove = function(e) {
    if(!start) return false;
    e.preventDefault();
    e.stopPropagation();
    var p = $.getTouchPosition(e);
    diffX = p.x - start.x;
    diffY = p.y - start.y;
    if(diffY > 0) {
      diffY = Math.sqrt(diffY);
    }

    noti.css("transform", "translate3d(0, "+diffY+"px, 0)");
  };
  var touchEnd = function() {
    noti.removeClass("touching");
    noti.attr("style", "");
    if(diffY < 0 && (Math.abs(diffY) > noti.height()*0.38)) {
      $.closeNotification();
    }

    if(Math.abs(diffX) <= 1 && Math.abs(diffY) <= 1) {
      noti.trigger("noti-click");
    }

    start = false;
  };

  var attachEvents = function(el) {
    el.on($.touchEvents.start, touchStart);
    el.on($.touchEvents.move, touchMove);
    el.on($.touchEvents.end, touchEnd);
  };

  $.notification = function(params) {
	var defaults = {
		title: undefined,
		text: undefined,
		media: undefined,
		time: 4000,
		onClick: undefined,
		onClose: undefined,
		data: undefined,
		template:  '<div class="notification-inner">' +
						'{if $media}<div class="notification-media">{$media}</div>{/if}' +
						'<div class="notification-content">' +
							'{if $title}<div class="notification-title">{$title}</div>{/if}' +
							'{if $text}<div class="notification-text">{$text}</div>{/if}' +
						'</div>' +
						'<div class="notification-handle-bar"></div>' +
					'</div>'
	};

    params = $.extend({}, defaults, params);
    noti = $(".notification");
    if(!noti[0]) {
      noti = $('<div class="notification"></div>').appendTo(document.body);
      attachEvents(noti);
    }

    noti.off("noti-click");
    if(params.onClick) noti.on("noti-click", function() {
      params.onClick(params.data);
    });

    noti.html($.template.compile(params.template)(params));

    noti.show();

    noti.addClass("notification-in");
    noti.data("params", params);

    var startTimeout = function() {
      if(timeout) {
        clearTimeout(timeout);
        timeout = null;
      }

      timeout = setTimeout(function() {
        if(noti.hasClass("touching")) {
          startTimeout();
        } else {
          $.closeNotification();
        }
      }, params.time);
    };

    startTimeout();

  };

  $.closeNotification = function() {
    timeout && clearTimeout(timeout);
    timeout = null;
    var noti = $(".notification").removeClass("notification-in").transitionEnd(function() {
      $(this).remove();
    });

    if(noti[0]) {
      var params = $(".notification").data("params");
      if(params && params.onClose) {
        params.onClose(params.data);
      }
    }
  };

}($);


+ function($) {
    "use strict";
    //安卓微信中使用scrollfix会有问题，因此只在ios中使用，安卓机器按照原来的逻辑
    if($.device.ios){
        var ScrollFix = function(elem) {

            var startY;
            var startTopScroll;

            elem = elem || document.querySelector(elem);

            if(!elem){
				return
			};

            elem.addEventListener('touchstart', function(event){
                startY = event.touches[0].pageY;
                startTopScroll = elem.scrollTop;

                if(startTopScroll <= 0)
                elem.scrollTop = 1;

            if(startTopScroll + elem.offsetHeight >= elem.scrollHeight)
                elem.scrollTop = elem.scrollHeight - elem.offsetHeight - 1;
            }, false);
        };

        var initScrollFix = function(){
            var prefix = $('.page-current').length > 0 ? '.page-current ' : '';
            var scrollable = $(prefix + ".page-content");
            new ScrollFix(scrollable[0]);
        };

        $(document).on($.touchEvents.move, ".page-current .bar",function(){
            event.preventDefault();
        });
        //监听ajax页面跳转
        $(document).on("pageLoadComplete", function(){
             initScrollFix();
        });
        //监听内联页面跳转
        $(document).on("pageAnimationEnd", function(){
             initScrollFix();
        });
        initScrollFix();
    }

}($);


//按键音功能
+ function($) {
	$.clickAudioPlay = function($page) {
		var event = '';
		var	autioHtml = '<audio id="smKeypressAudio" preload="auto" style="display:none">' +
							'<source src="'+ $.smConfig.clickAudioPlay.mp3 +'"></source>' +
							'<source src="'+ $.smConfig.clickAudioPlay.ogg +'"></source>' +
						'</audio>';

		$page.on('touchstart mousedown','a',function(){
			var state = $(this).attr('data-keypress-audio');
			if (event !== this && ($.smConfig.clickAudioPlay.state == true || state == 'true') && state !== 'false'){
				$(autioHtml)[0].play();
			}
			event = this;
		});
	};
}($);


/**
 * 发送验证码
 */
+ function($) {
	$.fn.captcha = function(option){
		var defaults = {
			wait:60,
			input:false,
			type:'POST',
			url:'',
			data:{},
			error:false,
			success:false
		};

		var $that = $(this);
		var opts = $.extend({}, defaults, option);
		var wait = opts.wait;

		var validate = function(val,type){
			var regExp = new RegExp(/^((\d{11})|^((\d{7,8})|(\d{4}|\d{3})-(\d{7,8})|(\d{4}|\d{3})-(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1})|(\d{7,8})-(\d{4}|\d{3}|\d{2}|\d{1}))$)$/);
			var retu = val.match(regExp);
			if (val == '' || val == 'undefined'){
				$.toast('请输入手机号码',2500,'',220);
				return false;
			}
			if(retu){
				return true;
			}else{
				$.toast('请输入正确的手机号码',2500,'',220);
				return false;
			}
		};

		var timer = function () {
			if (wait == 0) {
				$that.removeAttr('disabled').removeClass('disabled').val('重新获取');
				wait = opts.wait;
			} else {
				$that.attr('disabled', true).addClass('disabled').val('剩余' + wait + '秒');
				wait --;
				setTimeout(function () {
					timer();
				}, 1000)
			}
		};

		$that.click(function(){
			var check = true;
			if (opts.input){
				var value = $(opts.input).val();
				check = validate(value);
			};

			if (check){
				$.ajax({
					type:opts.type,
					dataType:opts.dataType,
					url:opts.url,
					storage:false,
					data:opts.data,
					error: function(x,t,e){
						if (opts.error){
							opts.error(x,t,e);
						}else{
							$.toast('验证码发送失败',2500,'',220);
						}
					},
					success: function(data){
						if (opts.success){
							opts.success({data:data,timer:timer})
						}
					}
				});
			}
		})
	}
}($);

+function($) {
    'use strict';

    var theHistory = window.history;

	var routerConfig = {
        sectionGroupClass: 'page-group',
        curPageClass: 'page-current',
        pageClass: 'page',
    };

	var direClass = {
			left  : ['page-from-center-to-left','page-from-right-to-center'],
			right : ['page-from-center-to-right','page-from-left-to-center'],
			up    : ['page-from-center-to-up','page-from-down-to-center'],
			down  : ['page-from-center-to-down','page-from-up-to-center'],
			flip  : ['','page-from-center-to-flip'],
			no    : ['','']
		};

	var direClassStr = function(){
			var classStr = '';
			for (var i in direClass){
				classStr += direClass[i].join(' ') + ' ';
			}
			return classStr.replace(/(\s*$)/g, "");
		};


    var Router = function() {

		this.$view = $('body');
		this.xhr = null;
		var currentUrl = location.href;

		this.sessionNames = {
            currentState: 'sm.router.currentState',
            maxStateId: 'sm.router.maxStateId'
        };

		var $currentPage = this._initCurrentSection(currentUrl,this.$view);

		if (!$currentPage) return;

		if (!customPageFilter('pageLoadStart',$currentPage[0],$currentPage[0])) return;

		this.changbarTabs($currentPage[1]);

		$currentPage[0].addClass(routerConfig.curPageClass);

		//改变浏览器标题
		if ($.smConfig.changeBrowserTitle){
			this._changeBrowserTitle($currentPage[0]);
		}

		if (theHistory.state === null) {
            var curState = {
                id: this._getNextStateId(),
                url: $currentPage[2],
                pageId: $currentPage[1],
				direction: $.smConfig.direction
            };
            theHistory.replaceState(curState, '', currentUrl);
            this._saveAsCurrentState(curState);
            this._incMaxStateId();
        }

        window.addEventListener('popstate', this._onPopState.bind(this));
    };

	//工具栏状态
	Router.prototype.changbarTabs = function(pageId) {
		var tabItem = this.$view.find('.bar-tab .tab-item[href="#'+pageId+'"]');
		if (tabItem.length > 0){
			tabItem.siblings().removeClass('active')
			tabItem.addClass('active');
		}
	}

    /**
     * 切换到 url 指定的块或文档
     *
     * 如果 url 指向的是当前页面，那么认为是切换块；
     * 否则是切换文档
     *
     * @param {String} url url
     */
    Router.prototype.load = function(url, direction) {

        if (this._isTheSameDocument(location.href, url)) {
			//内联页面切换
            this._switchToSection(url, direction);
        } else {
			//ajax 加载页面切换
            this._switchToDocument(url,direction,true);
        }
    };


    /**
     * 内联页面切换
     * @param {String} sectionId 待切换显示的块的 id
     * @private
     */
    Router.prototype._switchToSection = function(url,direction) {
        if (!url) return;
		var $currentPage = this._getCurrentSection(),
			urlObj = this.getUrlObject(url),
			sectionId = urlObj.fragment;

		if (sectionId == '') return;

		// 如果已经是当前页，不做任何处理
		if ($currentPage.attr('id') === sectionId) {
			return;
		}

		var $newPage = $('#' + sectionId);

		if (!$newPage.length){
			$(window).trigger('pageLoadError');
			return;
		}

		if (!customPageFilter('pageLoadStart',$currentPage,$newPage)) return;

        this._switchDirection(sectionId,$currentPage, $newPage, direction, false);

		this._pushState('#' + sectionId, urlObj, sectionId, direction);
    };


    /**
     * ajax加载页面
     */
    Router.prototype._switchToDocument = function(url, direction, isPushState) {
        var context = this;
		var urlObj = context.getUrlObject(url);

		if (context.xhr && context.xhr.readyState < 4) {
			context.xhr.onreadystatechange = function() {};
			context.xhr.abort();
			$(window).trigger('pageLoadCancel');
		}

		context.xhr = $.ajax({
			url: url,
			storage:false,
			success: $.proxy(function(data, status, xhr) {
				try {
					var $view  = context._parseXHR(data);
					var $form = context.$view.find('.' + routerConfig.sectionGroupClass);

					var $to = this._initCurrentSection(url,$view[0]);
						if (!$to) return ;

						$to[0].addClass(routerConfig.curPageClass);

					if (!customPageFilter('pageLoadStart',$form,$to[0])) return;

					context._appJScript($view,'pageLoadStart');

					context._switchDirection(url, $form, $to[0] ,direction , $view);
					if (isPushState){
						this._pushState(url, $to[2], $to[1], direction);
					}

				}catch(e) {
					location.href = url;
				}

			}, this),
			error: function(xhr, status, err) {
					if (err == 'Not Found'){
						$(window).trigger('pageLoadError');
					}else{
						//location.href = url;
					}
			},
			complete: function(xhr, status) {
				$(window).trigger('pageLoadComplete');
			}
		});
    };



    /**
     * 页面切换过渡效果
     *
     * @param $from
     * @param $to
     * @private
     */
    Router.prototype._switchDirection = function(url ,$from, $to, direction, prepDoc) {

		var	_this = this;

		_this.changbarTabs(url);

		if (prepDoc){
			prepDoc[0].append(prepDoc[1]);
			_this.$view.prepend(prepDoc[0]);
		}

		$from.removeClass(routerConfig.curPageClass);
		$to.addClass(routerConfig.curPageClass);

		//注册文档切换之后，动画开始之前
		if (!customPageFilter('pageSwitchEnd',$to,$to)) return;

		_this._appJScript(prepDoc,'pageSwitchEnd');

		if ($.smConfig.changeBrowserTitle){
			_this._changeBrowserTitle($to);
		}

		if (!$from.hasClass('show-bar-tab') && $to.hasClass('show-bar-tab')){
			$.showBartab();
		}

		if (!$from.hasClass('no-bar-tab') && $to.hasClass('no-bar-tab')){
			$.hideBartab();
		}

		if ($from.hasClass('no-bar-tab') && !$to.hasClass('no-bar-tab')){
			$.showBartab();
		}

		if (direction == 'no'){
			//初始化页面组件
			$.initPage($to);
			if (prepDoc){
				$from.remove();
				_this._appJScript(prepDoc,'pageInit');
			}
			return ;
		}

		//后退时使用反向动画
		if (typeof direction == 'object'){
			switch(direction.direction) {
				case 'no':
					direction = 'no';
					break;
				case 'left':
					direction = 'right';
					break;
				case 'right':
					direction = 'left';
					break;
				case 'up':
					direction = 'down';
					break;
				case 'down':
					direction = 'up';
					break;
				case 'flip':
					direction = 'flip';
					break;
				default:
					direction = 'right';
					break;
			}
		}

		var	directionClass = direClass[direction] || direClass[$.smConfig.direction];


		//切动画开始之前
		if (!customPageFilter('pageAnimationStart',$to,$to)) return;

		if (prepDoc) _this._appJScript(prepDoc,'pageAnimationStart');

		$from.removeClass(direClassStr).addClass(directionClass[0]);
		$to.removeClass(direClassStr).addClass(directionClass[1]);

		$from.animationEnd(function() {
			$from.removeClass(direClassStr);
			//如果是ajax的方式加载页面
			if (prepDoc){
				var $tridom = $from.find('.page.' + routerConfig.curPageClass);
				// 移除 document 前后，发送 beforePageRemove 和 pageRemoved 事件
				if (!customPageFilter('pageRemoveStart',$tridom,$tridom)) return;

				$from.remove();
				if (!customPageFilter('pageRemovedeEnd',$to,$tridom)) return;
			}
		});

		$to.animationEnd(function() {
			$to.removeClass(direClassStr);

			//页面动画执行结束
			if (!customPageFilter('pageAnimationEnd',$to,$to)) return;

			if (prepDoc) _this._appJScript(prepDoc,'pageAnimationEnd');

			//初始化页面组件
			$.initPage($to);

			if (prepDoc) _this._appJScript(prepDoc,'pageInit');
		});
    };


	/**
	 * 把一个字符串的 url 转为一个可获取其 base 和 fragment 等的对象
	 *
	 * @param {String} url url
	 * @returns {UrlObject}
	 */

	Router.prototype.getUrlObject = function(url) {
			var fullUrl = document.createElement('a');
				fullUrl.setAttribute('href', url);
				fullUrl = fullUrl.href;

			var fullHash = fullUrl.indexOf('#');
			var urlHash = url.indexOf('#');

            var baseUrl = fullHash === -1 ? fullUrl.slice(0) : fullUrl.slice(0, fullHash);
			var fragment = urlHash === -1 ? '' : url.slice(urlHash + 1);

            return {
                base: baseUrl,
                full: fullUrl,
                original: url,
                fragment: fragment
            };
    };

	//追加JS脚本
	Router.prototype._appJScript = function($page,defer) {
		if ($page){
			$.each($page[2][defer],function(i,$dom){
				if ($dom.src){
					if (!$.inScript(document.scripts,$dom.src)){
						$page[0].append($dom);
					}
				}else{
					$page[0].append($dom);
				}
			});
		}
	};

	Router.prototype._parseXHR = function(page) {
		var body = page.match(/<body[^>]*>([\s\S.]*)<\/body>/i),
			html = body ? body[1] : page,
			$html = $("<div>"+html+"</div>"),
			$pageGroup = $html.find('.'+routerConfig.sectionGroupClass),
			$extra = $pageGroup.siblings('.popup, .popover, .panel, .panel-overlay'),
			$script = $html.find('script');
			if ($script){
				var scriArr = {};
				$.each($script,function(i,script){
					var defer = $(script).attr('data-defer') || 'pageInit';
						scriArr[defer] = [];
				});

				$.each($script,function(i,script){
					var defer = $(script).attr('data-defer') || 'pageInit';
						scriArr[defer].push(script);
				});
			}

			if (!$pageGroup.length) {
				throw new Error('missing router view mark: ' + routerConfig.sectionGroupClass);
			}

		return [$pageGroup, $extra, scriArr];
	}


	/**
     * 改变浏览器的标题
     *
     * @private
     */
	Router.prototype._changeBrowserTitle = function($doc){
		var title = $doc.attr('title') || $doc.find('.page-title').text();
		if (title && title !==''){
			var ntitle = document.title = title;
			if (!ntitle){
				var $iframe = $('<iframe style="display:none;"></iframe>');
				$iframe.on('load',function() {
					setTimeout(function() {
						$iframe.off('load').remove();
					}, 0);
				}).appendTo(this.$view);
			}
		}
	};



    /**
     * 判断两个 url 指向的页面是否是同一个
     *
     * 判断方式: 如果两个 url 的 base 形式（不带 hash 的绝对形式）相同，那么认为是同一个页面
     *
     * @param {String} url
     * @param {String} anotherUrl
     * @returns {Boolean}
     * @private
     */
    Router.prototype._isTheSameDocument = function(url, anotherUrl) {
        return this.getUrlObject(url).base === this.getUrlObject(anotherUrl).base;
    };



    /**
     * 从 sessionStorage 中获取保存下来的「当前状态」
     *
     * 如果解析失败，那么认为当前状态是 null
     *
     * @returns {State|null}
     * @private
     */
    Router.prototype._getLastState = function() {
        var currentState = sessionStorage.getItem(this.sessionNames.currentState);
        try {
            currentState = JSON.parse(currentState);
        } catch(e) {
            currentState = null;
        }

        return currentState;
    };

    /**
     * 把一个状态设为当前状态，保存仅 sessionStorage 中
     *
     * @param {State} state
     * @private
     */
    Router.prototype._saveAsCurrentState = function(state) {
        sessionStorage.setItem(this.sessionNames.currentState, JSON.stringify(state));
    };

    /**
     * 获取下一个 state 的 id
     *
     * 读取 sessionStorage 里的最后的状态的 id，然后 + 1；如果原没设置，那么返回 1
     *
     * @returns {number}
     * @private
     */
    Router.prototype._getNextStateId = function() {
        var maxStateId = sessionStorage.getItem(this.sessionNames.maxStateId);
        return maxStateId ? parseInt(maxStateId, 10) + 1 : 1;
    };

    /**
     * 把 sessionStorage 里的最后状态的 id 自加 1
     *
     * @private
     */
    Router.prototype._incMaxStateId = function() {
        sessionStorage.setItem(this.sessionNames.maxStateId, this._getNextStateId());
    };


	/**
     * 初始化要显示的文档
     *
     * @returns {*}
     * @private
     */
    Router.prototype._initCurrentSection = function(url, $view, callback){

        //当前文档
		var urlObj = this.getUrlObject(url);
		var $page = $view.find('.' + routerConfig.pageClass);

		if (!$page.length) {
			console.error('Can\'t find ".page"');
			return;
		}

		var $currentPage = this._getCurrentSection($view);

		if (urlObj.fragment) {
			var $newCurrPage = $view.find('#' + urlObj.fragment);
		}

		if (!$currentPage.length) {
			$currentPage = $page.eq(0);
		}

		if ($newCurrPage && $newCurrPage.length && ($currentPage.attr('id') !== urlObj.fragment)) {
			$currentPage = $newCurrPage;
			$page.removeClass(routerConfig.curPageClass);
		}

		var currentPageId = $currentPage.attr('id');

		if (!currentPageId) {
			var currentPageId = 'page-' + (+new Date());
				$currentPage.attr('id',currentPageId);
        }

		return [$currentPage, currentPageId, urlObj];
    };


    /**
     * 获取当前显示的第一个 section
     *
     * @returns {*}
     * @private
     */
    Router.prototype._getCurrentSection = function($view) {
        return ($view ? $view : this.$view).find('.' + routerConfig.curPageClass).eq(0);
    };

    /**
     * 调用 history.forward()
     */
    Router.prototype.forward = function() {
        theHistory.forward();
    };

    /**
     * 调用 history.back()
     */
    Router.prototype.back = function() {
        theHistory.back();
    };

    /**
     * popState 事件关联着的后退处理
     *
     * 判断两个 state 判断是否是属于同一个文档，然后做对应的 section 或文档切换；
     * 同时在切换后把新 state 设为当前 state
     *
     * @param {State} state 新 state
     * @param {State} fromState 旧 state
     * @private
     */
    Router.prototype._back = function(state, fromState) {
        if (this._isTheSameDocument(state.url.full, fromState.url.full)) {
            var $newPage = $('#' + state.pageId);
            if ($newPage.length) {
                var $currentPage = this._getCurrentSection();
                this._switchDirection(state.pageId, $currentPage, $newPage, fromState ,false);
                this._saveAsCurrentState(state);
            } else {
                location.href = state.url.full;
            }
        } else {
            this._switchToDocument(state.url.full, fromState ,false);
            this._saveAsCurrentState(state);
        }
    };

    /**
     * popState 事件关联着的前进处理,类似于 _back，不同的是切换方向
     *
     * @param {State} state 新 state
     * @param {State} fromState 旧 state
     * @private
     */
    Router.prototype._forward = function(state, fromState) {
        if (this._isTheSameDocument(state.url.full, fromState.url.full)) {
            var $newPage = $('#' + state.pageId);
            if ($newPage.length) {
                var $currentPage = this._getCurrentSection();
                this._switchDirection(state.pageId , $currentPage, $newPage,state.direction,false);
                this._saveAsCurrentState(state);
            } else {
                location.href = state.url.full;
            }
        } else {
            this._switchToDocument(state.url.full,state.direction,false);
            this._saveAsCurrentState(state);
        }
    };

    /**
     * popState 事件处理
     *
     * 根据 pop 出来的 state 和当前 state 来判断是前进还是后退
     *
     * @param event
     * @private
     */
    Router.prototype._onPopState = function(event) {
        var state = event.state;
        if (!state || !state.pageId) {
            return;
        }

        var lastState = this._getLastState();

        if (!lastState) {
            console.error && console.error('Missing last state when backward or forward');
            return;
        }

        if (state.id === lastState.id) {
            return;
        }

        if (state.id < lastState.id) {
            this._back(state, lastState);
        } else {
            this._forward(state, lastState);
        }
    };

    /**
     * 页面进入到一个新状态
     *
     * 把新状态 push 进去，设置为当前的状态，然后把 maxState 的 id +1。
     *
     * @param {String} url 新状态的 url
     * @param {String} sectionId 新状态中显示的 section 元素的 id
     * @private
     */
    Router.prototype._pushState = function(url, urlObj, sectionId, direction) {

        var state = {
            id: this._getNextStateId(),
            pageId: sectionId,
			direction:direction,
            url: urlObj,
        };

        theHistory.pushState(state, '', url);
        this._saveAsCurrentState(state);
        this._incMaxStateId();
    };


    /**
     * 判断一个链接是否使用 router 来处理
     *
     * @param $link
     * @returns {boolean}
     */
    function isInRouterBlackList(href,$link) {
        var classBlackList = [
            'external',
            'tab-link',
            'open-popup',
            'close-popup',
            'open-panel',
            'close-panel'
        ];

		var protoWhiteList = [
            'http',
            'https'
        ];

		if ($link.hasClass('back')) {
			$.router.back();
			return ;
		}

		if (!href || href === '#' || /javascript:.*;/.test(href)) {
			return true;
		}

        for (var i = classBlackList.length -1 ; i >= 0; i--) {
            if ($link.hasClass(classBlackList[i])) {
                return true;
            }
        }

        //如果非noscheme形式的链接，且协议不是http(s)，那么路由不会处理这类链接
        if (/^(\w+):/.test(href) && protoWhiteList.indexOf(RegExp.$1) < 0) {
            return true;
        }

        if ($link.attr('external')) {
            return true;
        }

        return false;
    }

    /**
     * 自定义是否执行路由功能的过滤器
     *
     * 可以在外部定义 $.config.routerFilter 函数，实参是点击链接的 $ 对象。
     *
     * @param $link 当前点击的链接的 $ 对象
     * @returns {boolean} 返回 true 表示执行路由功能，否则不做路由处理
     */

    function customClickFilter($link) {
        var customRouterFilter = $.smConfig.routerFilter;
        if ($.isFunction(customRouterFilter)) {
            var filterResult = customRouterFilter($link);
            if (typeof filterResult === 'boolean') {
                return filterResult;
            }
        }

        return true;
    }

	/**
     * 自定义是否执行页面功能的过滤器
     *
     * 可以在外部定义 $.config.pageFilter 函数。
     *
     * @param $link 当前点击的链接的 $ 对象
     * @returns {boolean} 返回 true 表示执行路由功能，否则不做路由处理
     */
	function customPageFilter(event,$tridom,$page) {
        var pageFilter = $.smConfig.pageFilter;
		if ($.isFunction(pageFilter)){
			var filterResult = pageFilter(event,$page.attr('id'),$page);
			if (typeof filterResult === 'boolean'){
				return filterResult;
			}
		}
		$tridom.trigger(event, [$page.attr('id'), $page, $tridom]);
        return true;
    }


	//记忆页面滚动高度
	$.lastPosition =function(options) {
		if ( !sessionStorage) return;

		// 需要记忆模块的className
		var needMemoryClass = options.needMemoryClass || [];

		//让后退页面回到之前的高度
		var getMemory = function(pageId,arg){
		  needMemoryClass.forEach(function(item, index) {
			  if ($(item).length === 0) return;
			  // 遍历对应节点设置存储的高度
			  var memoryHeight = sessionStorage.getItem('sm.router.position.' + pageId);
			  arg.find(item).scrollTop(parseInt(memoryHeight));

		  });
		};

		//记住即将离开的页面的高度
		var updateMemory = function(pageId,$page) {
			// 存储需要记忆模块的高度
			needMemoryClass.forEach(function(item, index) {
				if ($(item).length === 0) return;
				sessionStorage.setItem('sm.router.position.' + pageId,$page.find(item).scrollTop());
			});
		};

		$(window).on('pageLoadStart', function(event,pageId,$page,$tridom) {
			updateMemory($tridom.find('.page.' + routerConfig.curPageClass).attr('id'),$tridom);
		});

		$(window).on('pageAnimationStart', function(event,pageId,$page) {
			getMemory(pageId,$page);
		});
	};

	//初始化页面中的JS组件
    $.initPage = function($page) {

		var $content = $page.hasClass('page-content') ?
                       $page :
                       $page.find('.page-content');

        $.initPullToRefresh($content);
		$.initInfiniteScroll($content);
		$.clickAudioPlay($content);

		if ($.initCalendar) $.initCalendar($content);
		if ($.initSwiper) $.initSwiper($content);
		if ($.initSwipeout) $.initSwipeout();

		//页面初始化完成
		if (!customPageFilter('pageInit',$page,$page)) return;
    };

    if ($.smConfig.pageLoading) {

        $(window).on('pageLoadStart', function(){
			$.showIndicator();
        });

        $(window).on('pageLoadCancel', function() {
            $.hideIndicator();
        });

        $(window).on('pageLoadComplete', function() {
            $.hideIndicator();
        });

        $(window).on('pageLoadError', function() {
            $.hideIndicator();
            $.toast('加载失败');
        });
    }

    $(window).on('pageAnimationStart', function(event,pageId,$page) {
        $.closeModal();
        $.closePanel();
		$.hideIndicator();
        $('body').removeClass('panel-closing');
        $.allowPanelOpen = true;
    });

    $(window).on('pageInit', function(event,pageId,$page) {
        $.hideIndicator();
        $.lastPosition({
            needMemoryClass: [
                '.page-content'
            ]
        });
    });

    window.addEventListener('pageshow', function(event) {
        if (event.persisted) {
            location.reload();
        }
    });

    $(function() {

        FastClick.attach(document.body);

		// 用户可选关闭router功能
		if (!$.smConfig.router) {
			return;
		}

		if (!$.supportStorage()){
			$.toast('由于您阻止了Cookie，无法继续访问',{duration:1000000});
			return;
		}

		//防止多次引入，重复实例化路由
		if (!$.router){
			$.router = new Router();
			$.initPage($.getCurrentPage());
		}

		$(document).on('click','a', function(e) {
			e.preventDefault();
			var $target = $(e.currentTarget);
			//启动路由过滤功能
			var filterResult = customClickFilter($target);
			var href = $target.attr('href');
			var direction = $target.attr('data-direction') || $.smConfig.direction;

			if (!filterResult) return;
			if (isInRouterBlackList(href,$target)) return;

			$.router.load(href, direction);
		});
    });
}($);
